先介紹怎麼用,而後說明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.
若是打算編寫多線程的服務程序,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
若是要啓動大量的子進程,能夠用進程池的方式批量建立子進程: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 0
,1
,2
,3
是馬上執行的,而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