Python多進程(multiprocessing)

  先介紹怎麼用,而後說明Python的多進程/多線程。python

  Linux和Unix操做系統提供了一個稱爲fork()的系統調用,普通的函數調用一次返回一次,該函數調用一次返回兩次,(也算實現了從1到2的突破)由於操做系統把當前進程(父進程)複製了一份(子進程)而後在子進程和父進程內返回,子進程永遠返回0,二父進程返回子進程的ID,這樣當建立不少子進程的時候,父進程多能一一記住本身兒子的識別碼。而子進程只須要調用getppid()就能夠獲得本身父進程的識別碼了。       當時就是由於Windows下沒有fork這個東西我才轉到linux下的,而後就一去不復返了。。。。linux

  正如你們所致Python的os模塊封裝了常見的系統調用,其中就有fork,能夠再Python中輕鬆的建立子進程:windows

import os

print('Process (%s) start...' % os.getpid())
# Only works on Unix/Linux/Mac:
pid = os.fork()
if pid == 0:
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
Process (13190) start...
I (13190) just created a child process (13191).
I am child process (13191) and my parent is 13190.

 

 multiprocessing

  若是打算編寫多線程的服務程序,Linux系統很方便,可是難道在windows下就沒辦法使用了麼? 因爲Python是跨平臺語言,天然也應該提供了一跨平臺的多進程支持,multiprocessing模塊就是跨平臺版本的多進程模塊。multiprocessing提供了一個Process類來表明一個進程對象,下面的例子演示了啓動一個子進程並等待其結束。多線程

 

from multiprocessing import Process
import os

# 子進程要執行的代碼
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()
    p.join()
    print('Child process end.')
Parent process 928.
Process will start.
Run child process test (929)...
Process end.

  建立子進程時,只須要傳入一個執行函數和函數的參數,建立一個Process實例,用start()方法啓動,join()方法能夠等待子進程結束後繼續向下運行,一般用於進程間的同步。app


 

Pool

  若是要啓動大量的子進程,能夠用進程池的方式批量建立子進程:dom

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')
Parent process 669.
Waiting for all subprocesses done...
Run task 0 (671)...
Run task 1 (672)...
Run task 2 (673)...
Run task 3 (674)...
Task 2 runs 0.14 seconds.
Run task 4 (673)...
Task 1 runs 0.27 seconds.
Task 3 runs 0.86 seconds.
Task 0 runs 1.41 seconds.
Task 4 runs 1.91 seconds.
All subprocesses done.

代碼解讀:async

  對Pool對象調用join()方法會等待全部子進程執行完畢,調用join()以前必須先調用close(),調用cose()以後就不能添加新的Process了。函數

  請注意輸出的結果,task 0123是馬上執行的,而task 4要等待前面某個task完成後才執行,這是由於Pool的默認大小在個人電腦上是4,所以,最多同時執行4個進程。這是Pool有意設計的限制,並非操做系統的限制。若是改爲:spa

p = Pool(5)

  就能夠同時跑五個進程了。  操作系統


 

子進程

  不少時候,子進程並非自身,而是一個外部進程。咱們建立了子進程後,還須要控制進程的輸入和輸出subprocess模塊可讓咱們很是方便的啓動一個子進程,而後控制其輸入和輸出。

  下面的例子演示瞭如何在Python代碼中運行命令nslookup www.python.org。這和命令行直接運行的結果是同樣的。

import subprocess

print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])
print('Exit code:', r)
$ nslookup www.python.org
Server:        127.0.1.1
Address:    127.0.1.1#53

Non-authoritative answer:
www.python.org    canonical name = python.map.fastly.net.
Name:    python.map.fastly.net
Address: 151.101.72.223

Exit code: 0

  若是子進程還須要輸入,則能夠經過communicate()方法輸入:

import subprocess

print('$ nslookup')
p = subprocess.Popen(['nslookup'],stdin = subprocess.PIPE,stdout = subprocess.PIPE,stderr = subprocess.PIPE)
output,err = p.communicate(b'set q = mx\npython.org\nexit\n')
print(output.decode('utf-8'))
print('Exit code:',p.returncode)

  上面的代碼至關於在執行命令nslookup的時候,手動輸入:

set q=mx
python.org
exit

  獲得結果:

$ nslookup
*** Invalid option: q
Server:        127.0.1.1
Address:    127.0.1.1#53

Non-authoritative answer:
Name:    python.org
Address: 23.253.135.79


Exit code: 0
相關文章
相關標籤/搜索