python學習筆記 - fork, multiprocessing

Python一直是一門對初學者很是友好的語言,在數據分析、Web 開發、網絡安全、網絡爬蟲等方面應用普遍。近年來,人工智能的興起使得 Python 更加火爆了。python

咱們在處理大量數據或者須要快速爬取多種網絡資源的時候,咱們沒法避免使用到進程。Cpython 解釋器中多線程涉及到 GIL 問題,咱們這裏暫不作考慮。linux

Python 實現多進程的方式有多種,咱們下面一一來學習一下吧。windows

fork

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()

上面的代碼用到了幾個函數,羅列以下:多線程

  • os.fork(),建立進程,在主進程中返回子進程的id,在子進程中返回0.
  • os.getpid() 獲取到當前進程的id。
  • os.getppid() 獲取當前進程父進程的id。

可是惟一遺憾的是,fork()函數只能在linuxunix系統中使用,不能在windows系統中使用。app

multiprocessing

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"

上面主要用到了函數

  • Process(target, attrs) 構造一個進程
  • process.start() 進程開始
  • process.join() 進程同步,Main進程序等待子程序完成後在執行後代碼。

須要注意的是,在windows下,若是子進程序不是在__main__中建立的,那麼就會出錯。由於windows在建立子進程的時候,會將建立它的py文件import進去。import進去機會執行,那麼就會不斷地建立子進程,因此會出錯。
所以在windows下,須要將其包含在__main__中。學習

Pool

上面的提到的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"
  • Pool(4)
  • join()

Wait for the worker processes to exit. One must call close() or terminate() before using join().即主進程會在.join()處等待worker進程們結束後再執行。

apply() 和 apply_async()

apply()apply_async()的區別就是前者是阻塞式的,後者是非阻塞式的。
阻塞式意思就是須要等待子進程完成後才能執行主線程後續的內容。
非阻塞意思就是無需等待子進程,二者是同步進行的。

map() 和 map_async()

跟高階函數map()一致,Poolmap()函數是將一個可迭代對象的每個元素做用域func
map也分阻塞和非阻塞。

imap() 和 imap_unordered()

imap 與 map的區別是,map是當全部的進程都已經執行完了,並將結果返回了,那麼才返回map()函數的一個list結果。
imap()則是當即返回一個iterable可迭代對象。其迭代隨着進行返回的結果而逐步迭代。

imap()和 imap_unordered()的區別

imap_unordered()不保證返回的結果順序與進程添加的順序一致。

怎麼取得進程的結果?

阻塞式函數:
Pool.apply()直接返回結果
Pool.map() 直接返回一個list
非阻塞式函數
Pool.apply_async()和Pool.map_async() 返回一個AsyncResult對象。
AsyncResult對象具備:get()函數能夠獲取結果。
imap() imap_unordered()則是返回可迭代函數。

一個有用的函數 multiprocessing.cpu_count()

multiprocess.cpu_count()能夠返回本計算機cpu的數量。咱們在新建一個進程池的時候,若是不填寫任何參數,那麼進程池的容量默認就是cpu的數量。

相關文章
相關標籤/搜索