Python的os
模塊封裝了常見的系統調用,其中就包括fork
,能夠在Python程序中輕鬆建立子進程python
fork能夠在Mac的Python上運行,但沒法再Windows下運行多線程
multiprocessing
模塊就是跨平臺版本的多進程模塊app
multiprocessing
模塊提供了一個Process
類來表明一個進程對象dom
#process_1.py from multiprocessing import Process import os def work(name): print("Run child process %s(%s)..." %(name,os.getpid())) if __name__=="__main__": print("Parent process %s." % os.getpid()) #建立進程實例 p = Process(target=work, args=("test",)) print("Child process will start...") p.start() p.join() print("Child process end.") 結果: Parent process 14628. Child process will start... Child process end.
建立子進程時,只須要傳入一個執行函數和函數的參數,建立一個Process
實例,用start()
方法啓動,join()
方法能夠等待子進程結束後再繼續往下運行,一般用於進程間的同步async
用進程池的方式批量建立子進程,啓動大量的子進程函數
#process_2.py 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(2) for i in range(3): p.apply_async(long_time_task, args=(i,)) print("Waiting for all subprocess done...") p.close() p.join() print("All subprocess done") 結果: Parent process 2096. Waiting for all subprocess done... All subprocess done
Pool
的默認大小是CPU的核數,這次運行環境cup核數爲1spa
subprocess
模塊可讓咱們很是方便地啓動一個子進程,而後控制其輸入和輸出線程
#process_3.py import subprocess print("$ nslookup www.python.org") r = subprocess.call(["nslookup", "www.python.org"]) print("Exit code:", r) 結果: $ nslookup www.python.org Exit code: 0
若是子進程還須要輸入,則能夠經過communicate()
方法code
Python的multiprocessing
模塊包裝了底層的機制,提供了Queue
、Pipes
等多種方式來交換數據對象
#process_4.py from multiprocessing import Process, Queue import os, time, random def write(q): print("Process to write: %s" %os.getpid()) for value in ["A","B","C"]: print("Put %s to queue..." % value) q.put(value) time.sleep(random.random()) def read(q): print("Process to read: %s" % os.getpid()) while True: value = q.get(True) print("Get %s from queue." % value) if __name__=="__mainn__": q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) pw.start() pr.start() pw.join() pr.terminate()
多任務能夠由多進程完成,也能夠由一個進程內的多線程完成
進程是由若干線程組成的,一個進程至少有一個線程
Python的標準庫提供了兩個模塊:_thread
和threading
,_thread
是低級模塊,threading
是高級模塊,對_thread
進行了封裝
絕大多數狀況下,咱們只須要使用threading
這個高級模塊
import time, threading def work(): n = 1 while n < 6: print("Work %s is running..." % str(n)) n+=1 t = threading.Thread(target = work, name = "workThread") t.start() t.join() print("%s ended." % threading.current_thread().name) 結果: Work 1 is running... Work 2 is running... Work 3 is running... Work 4 is running... Work 5 is running... MainThread ended.
因爲任何進程默認就會啓動一個線程,咱們把該線程稱爲主線程,主線程又能夠啓動新的線程,Python的threading
模塊有個current_thread()
函數,它永遠返回當前線程的實例
主線程實例的名字叫MainThread
,子線程的名字在建立時指定,名字僅僅在打印時用來顯示,徹底沒有其餘意義,若是不起名字Python就自動給線程命名爲Thread-1
,Thread-2
……
線程中,全部變量都由全部線程共享,因此,任何一個變量均可以被任何一個線程修改
線程之間共享數據最大的危險在於多個線程同時改一個變量,把內容給改亂了
當某個進程要更改數據時,先給它上鎖,其它線程不能更改。只有當鎖被釋放後,其它線程得到該鎖之後才能改
因爲鎖只有一個,不管多少線程,同一時刻最多隻有一個線程持有該鎖,因此,不會形成修改的衝突
Python雖然不能利用多線程實現多核任務,但能夠經過多進程實現多核任務。多個Python進程有各自獨立的GIL鎖,互不影響