Python一直是一門對初學者很是友好的語言,在數據分析、Web 開發、網絡安全、網絡爬蟲等方面應用普遍。近年來,人工智能的興起使得 Python 更加火爆了。python
咱們在處理大量數據或者須要快速爬取多種網絡資源的時候,咱們沒法避免使用到進程。Cpython 解釋器中多線程涉及到 GIL 問題,咱們這裏暫不作考慮。linux
Python 實現多進程的方式有多種,咱們下面一一來學習一下吧。windows
Linux/Unix系統提供了一個很是特殊的函數fork()
.該函數在調用以後,調用它的進程會被複制一份,包括當前的RAM和接下來要執行的代碼。
關於fork的具體內容能夠閱讀更多的文章:
http://blog.csdn.net/jason314...
http://blog.csdn.net/cywosp/a...安全
調用的fork()
函數,它在主進程中返回的是子進程的pid;它在子進程中反饋的是0
.
那麼,咱們就能夠根據fork()
函數返回的值來判斷是在主進程中仍是在子進程中了。
在Python中,爲咱們提供了os.fork()
。網絡
import os print "Process (%s) is running" % os.getpid() i = 100 pid = os.fork() if pid == 0: print "Son process (%s) is running" % os.getpid() else: print "Main process (%s) is running" % os.getpid()
上面的代碼用到了幾個函數,羅列以下:多線程
可是惟一遺憾的是,fork()函數只能在linuxunix系統中使用,不能在windows系統中使用。app
Python提供了跨平臺的多進程支持,multiprocessing. multiprocessing模塊提供了一個Process類表明一個進程。咱們能夠用Process建立一個進程。async
from multiprocessing import Process import time def son_process(name): time.sleep(2) print "Process %s is running" % name if __name__ == '__main__': son_process = Process(target=son_process, args=('Son',)) print "Son process is started" son_process.start() son_process.join() print "Son process is ended - Printed by Main Process"
上面主要用到了函數
須要注意的是,在windows下,若是子進程序不是在__main__
中建立的,那麼就會出錯。由於windows在建立子進程的時候,會將建立它的py文件import進去。import進去機會執行,那麼就會不斷地建立子進程,因此會出錯。
所以在windows下,須要將其包含在__main__
中。學習
上面的提到的Process主要用於建立一個進程,如何建立多個呢?Python在multiprocessing包裏爲咱們提供了Pool類。
咱們可使用Pool.apply_async(func, args)
函數來建立子進程。
代碼:
from multiprocessing import Pool import time def son_process(name): time.sleep(5) print "Process %s is running\n" % name pool = Pool(4) print "Son process is started" for x in range(0, 10): pool.apply_async(son_process, args=('son_%d'%x,)) pool.close() print "Mark" pool.join() print "Son process is ended - Printed by Main Process"
Wait for the worker processes to exit. One must call close() or terminate() before using join().即主進程會在.join()處等待worker進程們結束後再執行。
apply()
和apply_async()
的區別就是前者是阻塞式的,後者是非阻塞式的。
阻塞式意思就是須要等待子進程完成後才能執行主線程後續的內容。
非阻塞意思就是無需等待子進程,二者是同步進行的。
跟高階函數map()
一致,Pool
的map()
函數是將一個可迭代對象的每個元素做用域func
。
map也分阻塞和非阻塞。
imap 與 map的區別是,map是當全部的進程都已經執行完了,並將結果返回了,那麼才返回map()函數的一個list結果。
imap()則是當即返回一個iterable可迭代對象。其迭代隨着進行返回的結果而逐步迭代。
imap_unordered()不保證返回的結果順序與進程添加的順序一致。
阻塞式函數:
Pool.apply()直接返回結果
Pool.map() 直接返回一個list
非阻塞式函數
Pool.apply_async()和Pool.map_async() 返回一個AsyncResult對象。
AsyncResult對象具備:get()
函數能夠獲取結果。
imap() imap_unordered()則是返回可迭代函數。
multiprocess.cpu_count()
能夠返回本計算機cpu的數量。咱們在新建一個進程池的時候,若是不填寫任何參數,那麼進程池的容量默認就是cpu的數量。