目錄
multiprocessing模塊
仔細說來,multiprocess不是一個模塊而是python中一個操作、管理進程的包。 之所以叫multi是取自multiple的多功能的意思,在這個包中幾乎包含了和進程有關的所有子模塊。由於提供的子模塊非常多,為了方便大家歸類記憶,我將這部分大致分為四個部分:創建進程部分,進程同步部分,進程池部分,進程之間數據共享。
multiprocessing.Process模塊
process模塊是一個創建進程的模塊,借助這個模塊,就可以完成進程的創建。
process模塊介紹
Process([group [, target [, name [, args [, kwargs]]]]])
,由該類實例化得到的對象,表示一個子進程中的任務(尚未啟動)
強調:
- 需要使用關鍵字的方式來指定參數
- args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號
參數介紹:
- group參數未使用,值始終為None
- target表示調用對象,即子進程要執行的任務
- args表示調用對象的位置參數元組,
args=(1,2,'egon',)
- kwargs表示調用對象的字典,
kwargs={'name':'egon','age':18}
- name為子進程的名稱
方法介紹
p.start()
:啟動進程,並調用該子進程中的p.run()p.run()
:進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法p.terminate()
:強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵屍進程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那么也將不會被釋放,進而導致死鎖p.is_alive()
:如果p仍然運行,返回Truep.join([timeout])
:主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間,需要強調的是,p.join只能join住start開啟的進程,而不能join住run開啟的進程
3.2 屬性介紹
p.daemon
:默認值為False,如果設為True,代表p為后台運行的守護進程,當p的父進程終止時,p也隨之終止,並且設定為True后,p不能創建自己的新進程,必須在p.start()
之前設置p.name
:進程的名稱p.pid
:進程的pidp.exitcode
:進程在運行時為None、如果為–N,表示被信號N結束(了解即可)p.authkey
:進程的身份驗證鍵,默認是由os.urandom()
隨機生成的32字符的字符串。這個鍵的用途是為涉及網絡連接的底層進程間通信提供安全性,這類連接只有在具有相同的身份驗證鍵時才能成功(了解即可)
3.3 在windows中使用process模塊的注意事項
在Windows操作系統中由於沒有fork(linux操作系統中創建進程的機制),在創建子進程的時候會自動 import 啟動它的這個文件,而在 import 的時候又執行了整個文件。因此如果將process()直接寫在文件中就會無限遞歸創建子進程報錯。所以必須把創建子進程的部分使用if __name__ =='__main__ 判斷保護起來,import 的時候,就不會遞歸運行了。
Process的用法
一、jion用法
內部會調用wait(),等待執行完畢,回收pid
1.1 jion用法1
from multiprocessing import Process
import time
def foo():
print('process start')
time.sleep(2)
print('process end')
if __name__ == '__main__':
p = Process(target=foo) #創建子進程
p.start()#給操作系統發指令,開啟子進程
time.sleep(5)
p.join()#阻塞住主進程再等待子進程結束,然后再往下執行,(了解的是:內部會待用wait())
print('主進程')
#
process start
process end
主進程
1.2join用法2
from multiprocessing import Process
import time
def foo(x):
print('Process start')
time.sleep(x)
print('Process end')
if __name__ == '__main__':
p1 = Process(target=foo,args=(1,)) #進程傳參的固定模式
p2 = Process(target=foo,args=(2,))
p3 = Process(target=foo,args=(3,))
start = time.time()
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
end = time.time()
print(end-start)
print('主進程')
#進程是同時開啟的,不確定是哪一個先開啟,並且創建子進程需要時間,因此是3秒多
Process start
Process start
Process start
Process end
Process end
Process end
3.136319160461426
主進程
join用法2,優化
from multiprocessing import Process
import time
def foo(x):
print(f'process{x},start')
time.sleep(x)
print(f'process{x},end')
if __name__ == '__main__':
strart = time.time()
p_list = []
for i in range(1,4):
p=Process(target=foo,args=(i,))
p.start()
p_list.append(p)
print(p_list)
for p in p_list:
p.join()
end = time.time()
print(end-strart)
print('主進程')
#
[<Process(Process-1, started)>, <Process(Process-2, started)>, <Process(Process-3, started)>]
process1,start
process2,start
process3,start
process1,end
process2,end
process3,end
3.1335043907165527
主進程
1.3 join用法3
from multiprocessing import Process
import time
def foo(x):
print(f'process{x},start')
time.sleep(x)
print(f'process{x},end')
if __name__ == '__main__':
p1 = Process(target=foo,args=(1,))
p2 = Process(target=foo,args=(2,))
p3 = Process(target=foo,args=(3,))
start = time.time()
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
end = time.time()
print(end-start)
print('主進程結束')
#由於每一個進程都是在執行完后才會執行下一個進程,因此,時間是多余6s,創建子進程空間是需要時間的
process1,start
process1,end
process2,start
process2,end
process3,start
process3,end
6.339004039764404
主進程結束
二、查詢進程的pid
進程的pid,相當於人的id身份證一樣
from multiprocessing import Process,current_process
import os
import time
def task():
print('子進程 start')
print('在子進程中查詢自己的pid>',current_process().pid)
print('在子進程中查詢父進程的pid>',os.getppid())
time.sleep(200)
print('子進程end')
if __name__ == '__main__':
p = Process(target=task)
p.start()
print('在主進程中查看子進程的pid>',p.pid)#一定要寫在start之后,在給操作系統發送開啟子進程之后
print('主進程的pid>',os.getpid())
print('主進程的父進程的pid>',os.getppid())
print('主進程')
###
在主進程中查看子進程的pid> 11112
主進程的pid> 7320
主進程的父進程的pid> 2464
主進程
子進程 start
在子進程中查詢自己的pid> 11112
在子進程中查詢父進程的pid> 7320
三,查詢進程名name
from multiprocessing import Process,current_process
import time
def foo():
print('process start')
print('子進程的名字',current_process().name)
time.sleep(2)
print('process end')
if __name__ == '__main__':
p = Process(target=foo)
p2 = Process(target=foo)
p3 = Process(target=foo,name='ocean')
p.start()
p2.start()
p3.start()
print(p.name)
print(p2.name)
print(p3.name)
print('主進程')
################
Process-1
Process-2
ocean
主進程
process start
子進程的名字 Process-1
process start
子進程的名字 Process-2
process start
子進程的名字 ocean
process end
process end
process end
四、判斷進程的生死is_alive()
from multiprocessing import Process
import time
def foo():
print('process start')
time.sleep(2)
print('process end')
if __name__ == '__main__':
p = Process(target=foo)
p.start()
print(p.is_alive())#True,進程開啟,進程或者
time.sleep(5)
print(p.is_alive())#False 代碼運行完畢,進程死亡(系統判定,實際情況在具體分析)
print('主進程')
##############
True
process start
process end
False
主進程
五、殺死進程terminate()
from multiprocessing import Process
import time
def foo():
print('process start')
time.sleep(10)
print('process end')
if __name__ == '__main__':
p = Process(target=foo)
p.start()
p.terminate()#給操作系統發送一個請求,殺死進程的請求
print(p.is_alive())
p.join()
print(p.is_alive())
print('主進程')
###############
True
False
主進程
六、通過繼承Process類開啟進程
import os
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,name):
# super(MyProcess,self).__init__()
super().__init__()
self.name=name
def run(self):
print(os.getpid())
print('%s 正在和女主播聊天' %self.name)
if __name__ == '__main__':
p1=MyProcess('wupeiqi')
p2=MyProcess('yuanhao')
p3=MyProcess('nezha')
p1.start() # start會自動調用run
p2.start()
# p2.run()
p3.start()
p1.join()
p2.join()
p3.join()
print('主線程')
####################
1516
wupeiqi 正在和女主播聊天
4864
yuanhao 正在和女主播聊天
18228
nezha 正在和女主播聊天
主線程
七、進程間的數據隔離問題
from multiprocessing import Process
def work():
global n
n = 0
print('子進程內:',n)
if __name__ == '__main__':
n = 100
p = Process(target=work)
p.start()
print('主進程內:',n)
##############
主進程內: 100
子進程內: 0