進程:
python
Python 解釋器有一個全局解釋器鎖(PIL),致使每一個 Python 進程中最多同時運行一個線程,所以 Python 多線程程序並不能改善程序性能,不能發揮多核系統的優點,能夠經過這篇文章瞭解。數據庫
可是多進程程序不受此影響, Python 2.6 引入了 multiprocessing 來解決這個問題。這裏介紹 multiprocessing 模塊下的進程,進程同步,進程間通訊和進程管理四個方面的內容。 這裏主要講解多進程的典型使用,multiprocessing 的 API 幾乎是完複製了 threading 的API, 所以只需花少許的時間就能夠熟悉 threading 編程了編程
因爲GIL的存在,不少Python專家建議,多使用多進程,以便利用多核資源,而不是使用多線程。服務器
下面來下一個簡單生成線程的實例,以下:多線程
import multiprocessing import time def run(name): time.sleep(2) print("hello",name) if __name__ == "__main__": for i in range(5): p = multiprocessing.Process(target=run,args=("alex",)) p.start()
執行結果以下:
hello alex
hello alex
hello alex
hello alex
hello alex
上面一個程序就是多進程的實例,啓動了5個進程,可見,多進程是multiprocessing模塊;併發
multiprocessing.cpu_count()統計CPU的個數,即同時能夠運行幾個進程。cpu_count()統計CPU的個數,即幾核CPU。app
在Linux上,每個進程都是由父進程啓動的,根進程1,__init__()負責啓動;父進程,每一個進程一定有一個父進程。異步
下面咱們來寫一個程序,來看看進程裏面的一些概念:socket
import multiprocessing,os,time def info(title): print(title) print("Module name:",__name__) print("parent processing:",os.getppid()) #獲取線程父線程的PID print("son processing:",os.getpid()) #獲取線程的子線程PID print("\n") def func(name): info("\033[31m----------------函數func-------------------\033[0m") #啓動線程以後調用info()函數 print("name:",name) if __name__ == "__main__": info("\033[32m---------------主程序的進程信息-------------\033[0m") '''啓動一個進程''' p = multiprocessing.Process(target=func,args=("geng",)) p.start()
執行結果:
---------------主程序的進程信息-------------
Module name: __main__
parent processing: 2601
son processing: 6877
----------------函數func-------------------
Module name: __main__
parent processing: 6877
son processing: 6878
name: geng
上面程序中,__name__是指模塊名,os.getppid()是獲取父進程的ID,os.getpid()獲取本身的進程PID,咱們知道,進程都有本身的進程號,PID,async
上面的進程PID:2601是父進程,啓動了進程:6877,進程6877啓動了6878,那麼父進程2601是誰呢?這個進程是Pycharm的進程PID,程序的PID是由Pycharm進程啓動的,在Linux上,每個進程都是由父進程啓動的。
進程間通信
不一樣進程間內存是不共享的,要想實現兩個進程間的數據交換,能夠用如下方法:
咱們知道,線程之間數據是能夠共享的,以下:
from multiprocessing import Process,Queue import queue,threading def func(mess): q.put(mess) if __name__ == "__main__": q = queue.Queue() '''定義一個線程''' t = threading.Thread(target=func,args=("geng",)) t.start() print(q.get())
執行結果:
geng
從上面看,線程之間是能夠共享隊列的數據的,下面咱們來看下進程的狀況:
from multiprocessing import Process import queue,threading def func(): q.put(["alex","tom"]) if __name__ == "__main__": q = queue.Queue() '''定義一個線程''' p = Process(target=func) p.start() print(q.get()) 執行結果: Traceback (most recent call last): File "/home/zhuzhu/day10/進程數據共享.py", line 12, in <module> print(q.get()) File "/usr/lib/python3.5/queue.py", line 164, in get self.not_empty.wait() File "/usr/lib/python3.5/threading.py", line 293, in wait waiter.acquire() KeyboardInterrupt
可見,進程之間是不能隨便通訊的,要想實現進程之間的通訊,要使用進程Queue。以下:
from multiprocessing import Process,Queue def func(): q.put(["alex","tom"]) if __name__ == "__main__": q = Queue() '''定義一個線程''' p = Process(target=func) p.start() print(q.get())
執行結果:
['alex', 'tom']
可見,經過進程multiprocessing模塊中間的進程Queue可以實現不一樣進程之間的通信。進程之間的通訊狀況。
上面程序中,有兩個進程,父進程和子進程,父進程是程序自己,是由Pycharm啓動的,子進程p是由程序自己的父進程啓動的,父進程就是程序自己。二者之間是相互獨立的,想要實現數據的交流,要經過進程Queue。
Pipe(管道):管道函數返回一個由管默認爲雙相鏈接的鏈接對象(雙向)
經過管道之間實現數據的交換,管道有兩頭,鏈接兩個線程,parent_conn,child_conn = Pipe(),就像socket同樣,有客戶端和服務器端,經過發送和接收數據,就能實現管道之間的數據交換,如parent_conn.send()和child_conn.recv(),而且管道之間能夠接收和發送空的數據,都不會影響。以下:
'''線程之間正常是不能共享數據的,線程是相互獨立的,要想共享數據,要經過一些特殊的方法,下面經過Pipe管道實現數據共享''' '''Pipe實現數據共享是數據交換,與socket功能相似,一邊發送數據,一邊接收數據''' from multiprocessing import Process,Pipe def func(mess): child_conn.send(mess) print("子進程發送的數據:",mess)
child_conn.close() if __name__ == "__main__": parent_conn,child_conn = Pipe() #創建管道,管道有兩端,兩個線程一邊負責一端 while True: mess = input("請輸入您要交父線程的內容>>:") p = Process(target=func,args=(mess,)) p.start() p.join() data = parent_conn.recv() print("父進程接收到的消息:",data)
執行結果以下:
請輸入您要交父線程的內容>>:子進程發送數據,父進程接收數據
子進程發送的數據: 子進程發送數據,父進程接收數據
父進程接收到的消息: 子進程發送數據,父進程接收數據
請輸入您要交父線程的內容>>:管道有兩端,經過兩端管道的send,recv()實現數據的傳輸
子進程發送的數據: 管道有兩端,經過兩端管道的send,recv()實現數據的傳輸
父進程接收到的消息: 管道有兩端,經過兩端管道的send,recv()實現數據的傳輸
請輸入您要交父線程的內容>>:管道能夠收發空的消息
子進程發送的數據: 管道能夠收發空的消息
父進程接收到的消息: 管道能夠收發空的消息
請輸入您要交父線程的內容>>:
子進程發送的數據:
父進程接收到的消息:
請輸入您要交父線程的內容>>:上面經過收發空消息並無報錯。
子進程發送的數據: 上面經過收發空消息並無報錯。
父進程接收到的消息: 上面經過收發空消息並無報錯。
上面,咱們經過管道,實現了兩端數據的收發,Pipe(),有兩端,parent_conn,child_conn = Pipe(),管道,當完成管道數據交換後,關閉管道,
當Pipe()管道關閉以後,就不能交換數據了。
管道Pipe()有兩頭,一邊一個,兩邊負責收發各自的消息。
Pipe的源代碼以下:
class Connection(object): def send(self, obj): pass def recv(self): pass def fileno(self): return 0 def close(self): pass def poll(self, timeout=None): pass def send_bytes(self, buffer, offset=-1, size=-1): pass def recv_bytes(self, maxlength=-1): pass def recv_bytes_into(self, buffer, offset=-1): pass def __enter__(self): pass def __exit__(self, exc_type, exc_val, exc_tb): pass def Pipe(duplex=True): return Connection(), Connection()
Manager
進程之間相互獨立,Manager默認本身會加鎖,不用額外加鎖,擔憂兩個線程同時修改數據,這種事情不會發生,進程操做完了另一個進程纔會操做。
上面,咱們經過Pipe()管道,Queue隊列實現了線程之間的數據交換,可是也只是限於傳遞,各個線程之間是不能修改數據的,那麼如何修改數據呢?咱們能夠經過多線程裏面的Manager來修改線程之間的數據。以下:
"""以前都是共享數據,並不能在一個線程修改另一個線程的數據,下面經過Manager來修改數據""" from multiprocessing import Process,Manager import os def func(d,l): '''把Manger的生成的字典和列表實例當作參數傳入,並修改''' d[os.getpid()] = os.getppid() l.append(os.getpid()) print("子線程的列表:",l) if __name__ == "__main__": with Manager() as manager: #使用with定義 d = manager.dict() #生成一個字典,可在多個進程間共享和傳遞 l = manager.list() #定義一個Manager列表 p_lists = [] #定義一個線程空的字典,存放啓動的線程,稍後遍歷,確保都執行完畢 for k in range(10): p = Process(target=func,args=(d,l)) p.start() p_lists.append(p) for process in p_lists: process.join() print("字典:",d) print("列表:",l)
代碼執行結果:
子線程的列表: [9717]
子線程的列表: [9717, 9720]
子線程的列表: [9717, 9720, 9718]
子線程的列表: [9717, 9720, 9718, 9722]
子線程的列表: [9717, 9720, 9718, 9722, 9727]
子線程的列表: [9717, 9720, 9718, 9722, 9727, 9725]
子線程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733]
子線程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733, 9734]
子線程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733, 9734, 9731]
子線程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733, 9734, 9731, 9736]
字典: {9736: 9708, 9734: 9708, 9731: 9708, 9717: 9708, 9718: 9708, 9720: 9708, 9722: 9708, 9733: 9708, 9725: 9708, 9727: 9708}
上面代碼中,咱們使用了Manager()來定義了字典和列表,經過Manager()定義的字典和列表是能夠修改的,從結果能夠看出,修改爲功,可是全部主程序的代碼都要在with Manager() as manager:後面,否則會報錯。
若是不想注意縮進,即with Manager() as manager:全部語句縮進後面,能夠經過賦值,manager = Manager()也能夠,這樣就能在同一個縮進裏面執行程序,以下:
"""以前都是共享數據,並不能在一個線程修改另一個線程的數據,下面經過Manager來修改數據""" from multiprocessing import Process,Manager import os def func(d,l): '''把Manger的生成的字典和列表實例當作參數傳入,並修改''' d[os.getpid()] = os.getppid() l.append(os.getpid()) print("子線程的列表:",l) if __name__ == "__main__": manager = Manager() #使用with定義 d = manager.dict() #生成一個字典,可在多個進程間共享和傳遞 l = manager.list() #定義一個Manager列表 p_lists = [] #定義一個線程空的字典,存放啓動的線程,稍後遍歷,確保都執行完畢 for k in range(10): p = Process(target=func,args=(d,l)) p.start() p_lists.append(p) for process in p_lists: process.join() print("字典:",d) print("列表:",l)
執行結果以下:
子線程的列表: [10295]
子線程的列表: [10295, 10297]
子線程的列表: [10295, 10297, 10296, 10300, 10299]
子線程的列表: [10295, 10297, 10296, 10300, 10299]
子線程的列表: [10295, 10297, 10296, 10300, 10299]
子線程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302]
子線程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302]
子線程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307]
子線程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307, 10303]
子線程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307, 10303]
字典: {10305: 10286, 10307: 10286, 10309: 10286, 10295: 10286, 10296: 10286, 10297: 10286, 10299: 10286, 10300: 10286, 10302: 10286, 10303: 10286}
列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307, 10303]
上面使用的就是manager = Manager(),這樣咱們就沒必要過度擔憂縮進的問題了。
進程同步
若是不使用來自不一樣進程的鎖輸出,就很容易混淆起來。(Without using the lock output from the different processes is liable to get all mixed up.)
進程之間是相互獨立的,進程裏面爲何須要鎖呢?屏幕共享,鎖存在的意義,因爲屏幕共享,若是同時打印,就會出現錯誤,加鎖的目的是隻容許一個程序打印。
from multiprocessing import Process,Lock '''進程是相互獨立的,可是因爲打印的時候屏幕是共享的,加鎖的意義就是讓一個進程打印的時候,其餘進程暫時不打印,避免搶屏幕''' def func(mess): lock.acquire() try: print("\033[31m打印用戶輸入:%s\033[0m" %mess) finally: lock.release() #finally()不論是否有異常,都執行 if __name__ == "__main__": lock = Lock() mess = input("請輸入您要讓子線程打印的消息>>:") for i in range(10): p = Process(target=func,args=(mess,)) p.start()
執行結果:
請輸入您要讓子線程打印的消息>>:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
打印用戶輸入:進程之間加鎖的目的是防止屏幕打印錯亂
上面程序就是加鎖的狀況,加鎖是爲了不屏幕打印錯亂,有時候多進程同時打印會出現打印錯亂,因爲屏幕共享,不知道其餘線程何時執行完畢。
進程池
進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,若是進程池序列中沒有可供使用的進進程,那麼程序就會等待,直到進程池中有可用進程爲止。啓一個進程等於克隆一個父進程,CPU開銷很是大,在Windows啓動100個進程都很慢。啓一個進程就至關於克隆一個父進程的內存數據。
進程池中有兩個方法:
1.apply (串行)
2.apply_async (asynchronous異步)
apply方法的定義:
def apply(self, func, args=(), kwds={}):
'''
Equivalent of `func(*args, **kwds)`.
'''
assert self._state == RUN
return self.apply_async(func, args, kwds).get()
首先使用apply()方法,寫一個串行的進程池,固然這種方法不多見,不怎麼經常使用,以下:
from multiprocessing import Pool import time,os '''進程池,控制同一時間執行進程的個數,防止CPU運行吃力,啓用進程很耗費CPU''' def fun(): print("\033[31min the process of %s\033[0m" %os.getpid()) time.sleep(1) print("進程%s執行完畢" %os.getpid()) def bar(): '''當一個子線程執行完畢以後,父線程調用回調函數,好比公司發完工資以後,會發一條短信到你手機,這樣就能夠用回調函數''' print("您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!") if __name__ == "__main__": pool = Pool(processes=5) #定義同一時間最大運行進程的個數 for i in range(10): pool.apply(func=fun) print("The end!") pool.close() pool.join()
執行結果:
in the process of 13326
進程13326執行完畢
in the process of 13327
進程13327執行完畢
in the process of 13329
進程13329執行完畢
in the process of 13330
進程13330執行完畢
in the process of 13328
進程13328執行完畢
in the process of 13326
進程13326執行完畢
in the process of 13327
進程13327執行完畢
in the process of 13329
進程13329執行完畢
in the process of 13330
進程13330執行完畢
in the process of 13328
進程13328執行完畢
The end!
上面apply()是執行的串行進程,當一個進程執行完畢,纔會執行另一個,這樣就失去了併發的意義,要想執行併發,就要使用apply_async併發執行。
apply_async方法的定義:
def apply_async(self, func, args=(), kwds={}, callback=None,
error_callback=None):
'''
Asynchronous version of `apply()` method.
'''
if self._state != RUN:
raise ValueError("Pool not running")
result = ApplyResult(self._cache, callback, error_callback)
self._taskqueue.put(([(result._job, None, func, args, kwds)], None))
return result
上面的程序是串行的,如今咱們修改一下,讓進程多併發執行(即異步),以下:
from multiprocessing import Pool import time,os '''進程池,控制同一時間執行進程的個數,防止CPU運行吃力,啓用進程很耗費CPU''' def fun(): print("\033[32m-------------開始打印-------------------\033[0m") print("\033[31min the process of %s\033[0m" %os.getpid()) time.sleep(1) print("進程%s執行完畢" %os.getpid()) def bar(): '''當一個子線程執行完畢以後,父線程調用回調函數,好比公司發完工資以後,會發一條短信到你手機,這樣就能夠用回調函數''' print("您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!") if __name__ == "__main__": pool = Pool(processes=5) #定義同一時間最大運行進程的個數 for i in range(10): # pool.apply(func=fun) pool.apply_async(func=fun) print("The end!") pool.close() pool.join()
執行結果以下:
The end!
-------------開始打印-------------------
in the process of 13562
-------------開始打印-------------------
in the process of 13563
-------------開始打印-------------------
in the process of 13564
-------------開始打印-------------------
-------------開始打印-------------------
in the process of 13565
in the process of 13566
進程13563執行完畢
進程13562執行完畢
進程13564執行完畢
進程13566執行完畢
進程13565執行完畢
-------------開始打印-------------------
in the process of 13563
-------------開始打印-------------------
in the process of 13566
-------------開始打印-------------------
in the process of 13564
-------------開始打印-------------------
in the process of 13565
-------------開始打印-------------------
in the process of 13562
進程13563執行完畢
進程13565執行完畢
進程13566執行完畢
進程13562執行完畢
進程13564執行完畢
能夠看出,上面執行的結果是5個異步同時執行的,只有前5個進程執行完畢,纔會繼續執行,pool.apply_async()多併發異步執行,可是能夠看出,上面打印是按照誰先執行就先打印到屏幕上的,有點錯亂,固然這是多進程正常的狀況,而且要注意,進程池中,是先pool.close()關閉進程池,而後join()的,這個跟斷言有關,具體能夠看源代碼,可是必定要記住,必須有pool.join()否則會報錯,打印不了,這個是個坑。
回調,咱們常常會遇到這樣的問題?就是作完一件事情以後,想備註一下,或者告知一下,好比,公司發完公司,總會經過銀行發送一條消息到員工的手機上,如何操做呢?就能夠用到進程池中的回調,以下:
callback=func(函數名),只須要在apply_async(func=函數名,args=(參數),callback=回調函數名)就能實現回調,以下,咱們調用完線程以後,發送一條消息,以下:
from multiprocessing import Pool,Lock import time,os '''進程池,控制同一時間執行進程的個數,防止CPU運行吃力,啓用進程很耗費CPU''' def fun(): print("\033[32m-------------開始打印-------------------\033[0m") print("\033[31min the process of %s\033[0m" %os.getpid()) time.sleep(1) print("進程%s執行完畢" %os.getpid()) def bar(arg): '''當一個子線程執行完畢以後,父線程調用回調函數,好比公司發完工資以後,會發一條短信到你手機,這樣就能夠用回調函數''' print("您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!") if __name__ == "__main__": pool = Pool(processes=5) #定義同一時間最大運行進程的個數 for i in range(10): # pool.apply(func=fun) pool.apply_async(func=fun,callback=bar) print("The end!") pool.close() pool.join()
執行以下:
-------------開始打印-------------------
in the process of 13778
-------------開始打印-------------------
in the process of 13779
-------------開始打印-------------------
in the process of 13780
進程13776執行完畢
進程13777執行完畢
進程13778執行完畢
進程13780執行完畢
進程13779執行完畢
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
-------------開始打印-------------------
in the process of 13776
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
-------------開始打印-------------------
in the process of 13779
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
-------------開始打印-------------------
in the process of 13778
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
-------------開始打印-------------------
in the process of 13777
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
-------------開始打印-------------------
in the process of 13780
進程13777執行完畢
進程13779執行完畢
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
進程13776執行完畢
進程13778執行完畢
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
進程13780執行完畢
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!
上面程序中,咱們給apply_async()裏面的參數callback=bar,進行了賦值,讓執行完前面的線程以後,由主線程調用回調函數,記住是主線程調用的回調函數,而不是子線程調用的。下面程序咱們打印是誰調用的,就能驗證這一說法:
from multiprocessing import Pool,Lock import time,os '''進程池,控制同一時間執行進程的個數,防止CPU運行吃力,啓用進程很耗費CPU''' def fun(): print("\033[32m-------------開始打印-------------------\033[0m") print("\033[31min the process of %s\033[0m" %os.getpid()) time.sleep(1) print("進程%s執行完畢" %os.getpid()) print("子線程的PID:",os.getpid()) def bar(arg): '''當一個子線程執行完畢以後,父線程調用回調函數,好比公司發完工資以後,會發一條短信到你手機,這樣就能夠用回調函數''' print("您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!!") print("bar的線程PID:",os.getpid()) if __name__ == "__main__": pool = Pool(processes=5) #定義同一時間最大運行進程的個數 print("主線程的PID:",os.getpid()) for i in range(10): # pool.apply(func=fun) pool.apply_async(func=fun,callback=bar) print("The end!") pool.close() pool.join()
程序的執行結果以下:
主線程的PID: 13866 The end! -------------開始打印------------------- in the process of 13867 -------------開始打印------------------- in the process of 13869 -------------開始打印------------------- in the process of 13868 -------------開始打印------------------- in the process of 13870 -------------開始打印------------------- in the process of 13871 進程13868執行完畢 進程13867執行完畢 子線程的PID: 13867 子線程的PID: 13868 進程13870執行完畢 進程13871執行完畢 子線程的PID: 13870 子線程的PID: 13871 進程13869執行完畢 子線程的PID: 13869 -------------開始打印------------------- in the process of 13868 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 -------------開始打印------------------- in the process of 13869 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 -------------開始打印------------------- in the process of 13870 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! -------------開始打印------------------- in the process of 13867 bar的線程PID: 13866 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 -------------開始打印------------------- in the process of 13871 進程13868執行完畢 子線程的PID: 13868 進程13871執行完畢 子線程的PID: 13871 進程13869執行完畢 子線程的PID: 13869 進程13867執行完畢 子線程的PID: 13867 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 進程13870執行完畢 子線程的PID: 13870 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866 您好,您的工資已到帳,請注意查收,若有疑問,請聯繫人事部,謝謝!!! bar的線程PID: 13866
從上面的bar函數的線程PID能夠看出,bar的PID與主程序的PID是同樣的,說明是主程序調用的回調函數,若是pool.close()關閉以後不join(),則程序會關閉,無論其餘進程是否執行完畢。
操做完成數據庫後,寫一個日誌,爲何不用子進程,子進程會鏈接N次,使用callback只須要主程序鏈接一次便可,提升效率。
join() 主進程阻塞,等待子進程的退出, join方法要在close或terminate以後使用
有兩個值得提到的,一個是 callback,另一個是 multiprocessing.pool.AsyncResult。 callback 是在結果返回以前,調用的一個函數,這個函數必須只有一個參數,它會首先接收到結果。callback 不能有耗時操做,由於它會阻塞主線程。