multiprocessing
是一個使用相似於threading
模塊的API支持生成進程的包。該multiprocessing
軟件包提供本地和遠程併發。所以,該multiprocessing
模塊容許程序員充分利用給定機器上的多個處理器。能夠在Unix和Windows上運行。html
multipleprocessing文檔python
Process
(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)應該始終使用關鍵字參數調用構造函數程序員
threading.Thread
join
([timeout])join可防止產生殭屍進程,文檔中的編程指南中指出: 每次開啓一個新進程,全部未被join的進程會被join(也就是說非守護進程會自動被join),但即使如此也要明確地join啓動的全部進程。 所以若是不手動地join子線程,主進程也會等待子進程停止以後再停止編程
【另外join會影響守護進程的行爲,後面探討】併發
# -*- coding:utf-8 -*- import os from multiprocessing import Process def func(name): print('%s進程%d,父進程%d' % (name, os.getpid(), os.getppid())) ''' 在Windows中,Process開啓進程會再次導入此文件,爲防止導入時再次執行,須要添加 if __name__ == '__main__': ''' if __name__ == '__main__': func('主') p = Process(target=func, args=['子']) p.start() p.join()
結果:異步
主進程16452,父進程21852
子進程28472,父進程16452
若是子類重寫構造函數,則必須確保它在對進程執行任何其餘操做以前調用構造函數 [Process.__init__() ]。函數
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os class InheritTest(Process): def __init__(self, name): super().__init__() self.name = name def run(self): print('我是子進程%s,進程id=%d,父進程id=%d' % (self.name, os.getpid(), os.getppid())) time.sleep(2) if __name__ == '__main__': print('我是主進程, 進程id=%d,父進程id=%d' % (os.getpid(), os.getppid())) p = InheritTest('小明') p.start() p.join()
結果:spa
我是主進程, 進程id=18408,父進程id=21852
我是子進程小明,進程id=22640,父進程id=18408
若多個進程被join,阻塞時長是他們(包括主進程在這期間的執行時間)中執行時間最長的線程
# -*- coding:utf-8 -*- from multiprocessing import Process import time def short_time(): print('進程pid={},ppid={}'.format(os.getpid(), os.getppid())) time.sleep(2) def long_time(): print('進程pid={},ppid={}'.format(os.getpid(), os.getppid())) time.sleep(4) if __name__ == "__main__": p1 = Process(target=long_time) p2 = Process(target=short_time) p3 = Process(target=short_time) p4 = Process(target=short_time) p1.start() p2.start() p3.start() p4.start() print('1號進程阻塞中') p1.join() print('2號進程阻塞中') p2.join() print('3號進程阻塞中') p3.join() print('4號進程阻塞中') p4.join() ''' p1-p4異步執行,p1執行時間最長,那麼p1.join()阻塞完後,其它進程已經執行完了, p2-p4.join()不阻塞,直接執行 '''
結果:code
1號進程阻塞中
進程pid=26404,ppid=17928
進程pid=17960,ppid=17928
進程pid=15592,ppid=17928
進程pid=8724,ppid=17928
2號進程阻塞中
3號進程阻塞中
4號進程阻塞中
問1:只能在父進程中join子進程嗎?
問1的解釋: 在子進程中join其它同級的子進程會拋出異常 AssertionError: can only join a child process,所以只能在父進程中join子進程:
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os def func1(): time.sleep(2) print('func1 進程pid={} ppid={}'.format(os.getpid(), os.getppid())) def func2(p1): p1.join() print('func2 進程pid={} ppid={}'.format(os.getpid(), os.getppid())) if __name__ == "__main__": print('主進程id {}'.format(os.getpid())) p1 = Process(target=func1) p2 = Process(target=func2, args=[p1]) p2.start() # 和下面代碼互換會報另外一個異常 p1.start()
主進程id 14796
Process Process-2:
Traceback (most recent call last):
...............
AssertionError: can only join a child process
func1 進程pid=30100 ppid=14796
【單獨調用run不會開啓子進程】
start()
方法返回到子進程終止的那一刻,進程對象處於活動狀態。
None
。
# -*- coding:utf-8 -*- import os from multiprocessing import Process import time def func(name): print('%s進程%d,父進程%d' % (name, os.getpid(), os.getppid())) if name != '主': time.sleep(2) if __name__ == '__main__': func('主') p = Process(target=func, args=['子']) p.start() print('p.pid()', p.pid) print('p.is_alive()=', p.is_alive()) print('p.exitcode=', p.exitcode) p.join() print('p.exitcode=', p.exitcode) print('p.is_alive()=', p.is_alive())
結果
主進程1548,父進程21852
p.pid() 24000
p.is_alive()= True
p.exitcode= None
子進程24000,父進程1548
p.exitcode= 0
p.is_alive()= False
daemon
start()
調用以前設置 它。
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os def daemon_func(): time.sleep(2) print('守護進程pid={},ppid={}'.format(os.getpid(), os.getppid())) if __name__ == "__main__": print('主進程id {}'.format(os.getpid())) p = Process(target=daemon_func) p.daemon = True p.start() # p.join()
當p.join()註釋後,主進程停止,守護進程也停止,所以輸出:
主進程id 15096
若取消註釋,守護進程被join,主進程會等待此守護進程,輸出爲:
主進程id 10896
守護進程pid=19404,ppid=10896
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os # 守護進程p1執行 def daemon_func(): time.sleep(1) print('daemon_func 進程pid={},ppid={}'.format(os.getpid(), os.getppid())) # 非守護進程p2執行 def non_daemon_func(): time.sleep(2) print('non_daemon_func 進程pid={},ppid={}'.format(os.getpid(), os.getppid())) if __name__ == "__main__": print('主進程id {}'.format(os.getpid())) p1 = Process(target=daemon_func) p1.daemon = True p2 = Process(target=non_daemon_func) p1.start() p2.start()
主進程執行完當即停止守護進程(主進程此時本身沒停止),主進程等待非守護進程,而後停止
所以執行結果是:
主進程id 24588
non_daemon_func 進程pid=3772,ppid=24588 ### 這裏ppid是24588,而不是1,說明主進程還未停止
(4.1)守護進程被join:
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os # 守護進程p1執行 def daemon_func(): time.sleep(1) print('daemon_func 進程pid={},ppid={}'.format(os.getpid(), os.getppid())) # 非守護進程p2執行 def non_daemon_func(): time.sleep(2) print('non_daemon_func 進程pid={},ppid={}'.format(os.getpid(), os.getppid())) if __name__ == "__main__": print('主進程id {}'.format(os.getpid())) p1 = Process(target=daemon_func) p1.daemon = True p2 = Process(target=non_daemon_func) p1.start() p2.start() p1.join() # join守護進程
主進程執行完後沒停止守護進程,並等待非守護進程執行完:
主進程id 24416
daemon_func 進程pid=27312,ppid=24416
non_daemon_func 進程pid=12408,ppid=24416
守護進程睡三秒,主進程仍會等待守護進程執行完:
主進程id 20336
non_daemon_func 進程pid=24528,ppid=20336
daemon_func 進程pid=16596,ppid=20336
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os # 守護進程p1執行 def daemon_func(): time.sleep(1) print('daemon_func 進程pid={},ppid={}'.format(os.getpid(), os.getppid())) # 非守護進程p2執行 def non_daemon_func(): time.sleep(2) print('non_daemon_func 進程pid={},ppid={}'.format(os.getpid(), os.getppid())) if __name__ == "__main__": print('主進程id {}'.format(os.getpid())) p1 = Process(target=daemon_func) p1.daemon = True p2 = Process(target=non_daemon_func) p1.start() p2.start() p2.join() # join非守護進程
非守護進程被join,主進程等待非守護進程,非守護進程停止後,當即停止守護進程。
------------------------------------------------------------------------------ 注意【1.主進程只join非守護進程】和【2.主進程沒有join任何進程】的區別:
1: 主進程會被join阻塞,等到非守護進程停止後,停止守護進程
2: 主進程執行完當即停止守護進程,若非守護進程未停止,等待
其實都是主進程的代碼執行完畢後,才停止子守護進程,只是1包含了手動join進程的代碼,阻塞後代碼纔算執行完畢。
-----------------------------------------------------------------
守護進程睡1秒後,非守護進程還在睡,主進程被阻塞住,所以守護進程有輸出
主進程id 11284
daemon_func 進程pid=5308,ppid=11284
non_daemon_func 進程pid=30364,ppid=11284
守護進程睡3秒後,非守護進程在2秒時睡醒後停止,主進程便在此時停止守護進程,所以守護進程沒有輸出
主進程id 24912
non_daemon_func 進程pid=19892,ppid=24912
join在不少地方都有用到,預知join的行爲併合理利用join,避免產生死鎖
停止進程,在Unix上是用SIGTERM信號完成的;在Windows上,使用TerminateProcess();
注意,退出處理程序和finally子句等不會被執行
被停止進程的子進程不會被停止
避免使用此方法:使用該方法中止進程可能致使進程當前使用的任何共享資源被破壞或不可用於其它進程,最好只考慮該方法用在從不使用共享資源的進程上
參考:
若有意見或建議,一塊兒交流;若有侵權,請告知刪除。