1.自定義行程
自定義行程類,繼承Process類,重寫run方法(重寫Process的run方法),
from multiprocessing import Process import time import os class MyProcess(Process): def __init__(self, name): ##重寫,需要__init__,也添加了新的引數,
##Process.__init__(self) 不可以省略,否則報錯:AttributeError:'XXXX'object has no attribute '_colsed' Process.__init__(self) self.name = name def run(self): print("子行程(%s-%s)啟動" % (self.name, os.getpid())) time.sleep(3) print("子行程(%s-%s)結束" % (self.name, os.getpid())) if __name__ == '__main__': print("父行程啟動") p = MyProcess("Ail") # 自動呼叫MyProcess的run()方法 p.start() p.join() print("父行程結束") # 輸出結果 父行程啟動 子行程(Ail-38512)啟動 子行程(Ail-38512)結束 父行程結束
2.行程與執行緒
多行程適合在CPU密集型操作(CPU操作指令比較多,如科學計算、位數多的浮點計算);
多執行緒適合在IO密集型操作(讀寫資料操作比較多的,比如爬蟲、檔案上傳、下載)
執行緒是并發,行程是并行:行程之間互相獨立,是系統分配資源的最小單位,同一個行程中的所有執行緒共享資源,
行程:一個運行的程式或代碼就是一個行程,一個沒有運行的代碼叫程式,行程是系統進行資源分配的最小單位,行程擁有自己的記憶體空間,所以,行程間資料不共享,開銷大,
行程是程式的一次動態執行程序,每個行程都擁有自己的地址空間、記憶體、資料堆疊以及其它用于跟蹤執行的輔助資料,作業系統負責其上所有行程的執行,作業系統會為這些行程合理地分配執行時間,
執行緒:調度執行的最小單位,也叫執行路徑,不能獨立存在,依賴行程的存在而存在,一個行程至少有一個執行緒,叫做主執行緒,多個執行緒共享記憶體(資料共享和全域變數),因此提升程式的運行效率,
執行緒是作業系統能夠進行運算調度的最小單位,它被包含在行程之中,是行程中的實際運作單位,一條執行緒指的是行程中一個單一順序的控制流,一個行程中可以并發多個執行緒,每條執行緒并行執行不同的任務,一個執行緒是一個execution context(執行背景關系),即一個CPU執行時所需要的一串指令,
主執行緒:主執行緒就是創建執行緒行程中產生的第一個執行緒,也就是main函式對應的執行緒,
協程:用戶態的輕量級執行緒,調度由用戶控制,擁有自己的暫存器背景關系和堆疊,切換基本沒有內核切換的開銷,切換靈活,
行程和執行緒的關系

3.多執行緒
作業系統通過給不同的執行緒分配時間片(CPU運行時長)來調度執行緒,當CPU執行完一個執行緒的時間片后就會快速切換到下一個執行緒,時間片很短而且切換速度很快,以至于用戶根本察覺不到,多個執行緒根據分配的時間片輪流被CPU執行,如今絕大多數計算機的CPU都是多核的,多個執行緒在作業系統的調度下,能夠被多個CPU并行執行,程式的執行速度和CPU的利用效率大大提升,絕大對數主流的編程語言都能很好地支持多執行緒,然而,Python由于GIL鎖無法實作真正的多執行緒,
記憶體中的執行緒

4.Thread類方法
(1)start() --開始執行該執行緒;
(2)run() --定義執行緒的方法(開發者可以在子類中重寫);標準的 run() 方法會對作為 target 引數傳遞給該物件構造器的可呼叫物件(如果存在)發起呼叫,并附帶從 args 和 kwargs 引數分別獲取的位置和關鍵字引數,
(3)join(timeout=None) --直至啟動的執行緒終止之前一直掛起;除非給出了timeout(單位秒),否則一直被阻塞;因為 join() 總是回傳 None ,所以要在 join() 后呼叫 is_alive() 才能判斷是否發生超時 -- 如果執行緒仍然存活,則 join() 超時,一個執行緒可以被 join() 很多次,如果嘗試加入當前執行緒會導致死鎖, join() 會引起 RuntimeError 例外,如果嘗試 join() 一個尚未開始的執行緒,也會拋出相同的例外,
(4)is_alive() --布林值,表示這個執行緒是否還存活;當 run() 方法剛開始直到 run() 方法剛結束,這個方法回傳 True ,
(5)threading.current_thread()--回傳當前對應呼叫者的控制執行緒的 Thread 物件,例如,獲取當前執行緒的名字,可以是current_thread().name,
5.多執行緒與多行程 小Case
from threading import Thread from multiprocessing import Process import os def work(): print('hello,',os.getpid()) if __name__ == '__main__': # 在主行程下開啟多個執行緒,每個執行緒都跟主行程的pid一樣 t1 = Thread(target=work) # 開啟一個執行緒 t2 = Thread(target=work) # 開啟兩個執行緒 t1.start() ##start()--It must be called at most once per thread object.It arranges for the object's run() method to be
## invoked in a separate thread of control.This method will raise a RuntimeError if called more than once on the
## same thread object. t2.start() print('主執行緒/主行程pid', os.getpid()) # 開多個行程,每個行程都有不同的pid p1 = Process(target=work) p2 = Process(target=work) p1.start() p2.start() print('主執行緒/主行程pid',os.getpid())
來源于:https://cloud.tencent.com/developer/article/1175618
6.Thread 的生命周期
執行緒的狀態包括:創建、就緒、運行、阻塞、結束,
(1) 創建物件時,代表 Thread 內部被初始化;
(2) 呼叫 start() 方法后,thread 會開始進入佇列準備運行,在未獲得CPU、記憶體資源前,稱為就緒狀態;輪詢獲取資源,進入運行狀態;如果遇到sleep,則是進入阻塞狀態;
(3) thread 代碼正常運行結束或者是遇到例外,執行緒會終止,
7.自定義執行緒
(1)定義一個類,繼承Thread;
(2)重寫__init__ 和 run();
(3)創建執行緒類物件;
(4)啟動執行緒,
import time import threading class MyThread(threading.Thread): def __init__(self,num): super().__init__() ###或者是Thread.__init__() self.num = num def run(self): print('執行緒名稱:', threading.current_thread().getName(), '引數:', self.num, '開始時間:', time.strftime('%Y-%m-%d %H:%M:%S')) if __name__ == '__main__': print('主執行緒開始:',time.strftime('%Y-%m-%d %H:%M:%S')) t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start() t1.join() t2.join() print('主執行緒結束:', time.strftime('%Y-%m-%d %H:%M:%S'))
8.執行緒共享資料與GIL(全域解釋器鎖)
如果是全域變數,則每個執行緒是共享的;
GIL鎖:可以用籃球比賽的場景來模擬,把籃球場看作是CPU,一場籃球比賽看作是一個執行緒,如果只有一個籃球場,多場比賽就要排隊進行,類似于一個簡單的單核多執行緒的程式;如果由多塊籃球場,多場比賽同時進行,就是一個簡單的多核多執行緒的程式,然而,Python有著特別的規定:每場比賽必須要在裁判的監督之下才允許進行,而裁判只有一個,這樣不管你有幾塊籃球場,同一時間只允許有一個場地進行比賽,其它場地都將被閑置,其它比賽都只能等待,
9.GIL 和 Lock
GIL保證同一時間內一個行程可以有多個執行緒,但只有一個執行緒在執行;鎖的目的是為了保護共享的資料,同一時間只能有一個執行緒來修改共享的資料,
類為threading.Lock
它有兩個基本方法, acquire() 和 release() ,
當狀態為非鎖定時, acquire() 將狀態改為 鎖定 并立即回傳,當狀態是鎖定時, acquire() 將阻塞至其他執行緒呼叫 release() 將其改為非鎖定狀態,然后 acquire() 呼叫重置其為鎖定狀態并回傳,
release() 只在鎖定狀態下呼叫; 它將狀態改為非鎖定并立即回傳,如果嘗試釋放一個非鎖定的鎖,則會引發 RuntimeError 例外,
Caese 如下:
from threading import Thread from threading import Lock import time
number = 0
def task(lock): global number lock.acquire() ##持有鎖 for i in range(100000)
number += 1
lock.release() ##釋放鎖 if __name__ == '__main__': lock=Lock() t1 = Thread(target=task,args=(lock,)) t2 = Thread(target=task,args=(lock,))
t3 = Thread(target=task,args=(lock,))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print('number:',number)
參考
1.Python3多行程multiprocessing模塊的使用
https://www.jianshu.com/p/a5f10c152c20
2.python3--threading模塊(執行緒)
https://cloud.tencent.com/developer/article/1175618
3.threading --- 基于執行緒的并行
https://docs.python.org/zh-cn/3.7/library/threading.html
4.python 并發編程 多執行緒 GIL與Lock
https://www.cnblogs.com/mingerlcm/p/9026090.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/345516.html
標籤:其他
上一篇:Spring01_day01
下一篇:C++實作一個SOAP客戶端
