Python基礎知識(22):程式和執行緒(Ⅰ)
1、多程式
(1)fork
Python的os
模組封裝了常見的系統呼叫,其中就包括fork
,可以在Python程式中輕鬆建立子程式
fork可以在Mac的Python上執行,但無法再Windows下執行
(2)multiprocess
multiprocessing
模組就是跨平臺版本的多程式模組
multiprocessing
模組提供了一個Process
類來代表一個程式物件
#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()
方法可以等待子程式結束後再繼續往下執行,通常用於程式間的同步
(3)pool
用程式池的方式批量建立子程式,啟動大量的子程式
#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核數為1
(4)子程式
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()
方法
(5)程式間通訊
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
……
LOCK
執行緒中,所有變數都由所有執行緒共享,所以,任何一個變數都可以被任何一個執行緒修改
執行緒之間共享資料最大的危險在於多個執行緒同時改一個變數,把內容給改亂了
當某個程式要更改資料時,先給它上鎖,其它執行緒不能更改。只有當鎖被釋放後,其它執行緒獲得該鎖以後才能改
由於鎖只有一個,無論多少執行緒,同一時刻最多隻有一個執行緒持有該鎖,所以,不會造成修改的衝突
多核CPU
Python雖然不能利用多執行緒實現多核任務,但可以通過多程式實現多核任務。多個Python程式有各自獨立的GIL鎖,互不影響