python高階 七 多執行緒併發

2022-05-29 09:54:10 字數 4909 閱讀 6473

一、併發和並行

併發:任務數》cpu核數,通過系統的各任務排程演算法,來回切換,實現多個任務「一起」執行,實際上不是真正同時一起執行,只是切換執行的速度相當快,看上去是一起執行的而已;

並行:任務數<=cpu核數,是真正的一起同時執行。

同步:同步是指**呼叫io操作時,必須等待io操作完成返回才呼叫的方式,只有乙個主線;

非同步:非同步是指**呼叫io操作時,不必等待io操作完成返回才呼叫的方式,存在多條主線;

from threading import

thread

import

time

deftimer(fun):

time1 =time.time()

fun(*args,**kwargs)

time2=time.time()

print("

當前函式執行時間為:{}

".format(time2-time1))

return time2-time1

return

defwork1():

for i in range(6):

time.sleep(1)

print(f'

第次澆花中')

defwork2(name):

for i in range(5):

time.sleep(1)

print(f'

第次打牆中')

#同步執行如下,需用11s多

@timer

defmain():

work1()

work2()

#非同步執行,只用6s多

@timer

defmain2():

t1=thread(target=work2,args=('musen',)) # 執行緒執行函式的傳參或者

thread(target=work2,kwargs=) 這種方式傳參

t1.start() 

#初始新執行緒的準備工作並執行,不一定在主線程後執行,也有可能先於主線程

print("

打牆任務非同步執行中

") work1() main() main2()

threading模組講解:

建立執行緒物件: t1=threading.thread(target=func)    func為指定執行緒執行的任務函式

thread類常用方法、屬性:

1.start() :啟動執行緒活動。

2.run():這個方法描述執行緒的活動,可以在子類中覆蓋這個方法。

3.join(timeout=none):設定主線程等待子執行緒執行結束後再繼續執行。可以設定乙個timeout引數,避免無休止的等待。因為兩個執行緒順序完成,看起來象乙個執行緒,所以稱為執行緒的合併.

通過傳給join乙個引數來設定超時,也就是超過指定時間join就不在阻塞程序。而在實際應用測試的時候發現並不是所有的執行緒在超時時間內都結束的,而是順序執行檢驗是否在time_out時間內超時,例如,超時時間設定成2s,前面乙個執行緒在沒有完成的情況下,後面執行緒執行join會從上乙個執行緒結束時間起再設定2s的超時。

4.name:執行緒名

5.getname(): 返回執行緒名

6.setname(): 設定執行緒名

7.ident:執行緒的識別符號

8.is_alive(): 返回執行緒是否活動

9.daemon:布林值,表示這個執行緒是否是守護執行緒

threading.active_count():這個函式返回當前執行緒的個數,這個程式的值也等於列表 

threading.current_thread():返回當前的執行緒物件

threading.enumereate():返回當前執行執行緒的列表

threading.main_thread():返回主線程,正常情況下,主線程就是python 直譯器執行時開始的那個執行緒。

# 定義執行緒類

import

time

from threading import

thread

deftimer(fun):

time1 =time.time()

fun(*args,**kwargs)

time2=time.time()

print("

當前函式執行時間為:{}

".format(time2-time1))

return time2-time1

return

class

mytread(thread):

def __init__(self):

super().__init__(*args,**keargs)

self.url=url

defrun(self):

headers=

for i in range(100):

#res=requests.get('

',headers=headers)

res=requests.get(url=self.url,headers=headers) 

print

(res)

@timer

defmain():

t_list=

for i in range(10):

#t=mytread()

t=mytread('')

t.start()

#t.join() 如果放在這裡,就會變成單執行緒執行,乙個執行完再建乙個子執行緒

#遍歷所有子執行緒,設定子執行緒全部執行完後再執行主線程

for j in

t_list:

j.join()

if__name__=="

__main__":

main()

執行緒之間哪些操作會引起切換?

1. io耗時操作:網路、檔案、輸入等耗時的io操作,會自動進行執行緒切換;

2. 執行緒執行時間達到一定的閥值時會執行切換;

100萬bug的解決方法:

1. 通過加鎖來處理

2. 通過儲存佇列來做

from threading import

thread,lock

num=0

defwork1():

global num

for i in range(1000000):

meta.acquire() #加鎖

num+=1meta .release() #解鎖

defwork2():

global num

for i in range(1000000):

meta.acquire() #加鎖

num+=1meta .release() #解鎖

meta=lock() #

建立一把鎖

defmain():

t1=thread(target=work1)

t2=thread(target=work2)

t1.start()

t2.start()

t1.join()

t2.join()

print

(num)

if__name__=='

__main__':

main()

gil全域性直譯器鎖:

io密集型任務: cpu占用少,大部分時間在io操作等待上。這種適合多執行緒來完成

cpu密集型任務:cpu占用多,需要進行大量的計算。這種適合單執行緒來完成。

關於gil的幾點說明:

1.python語言和gil沒有關係,僅僅是由於歷史原因在cpython虛擬機器(直譯器)上,難以移除gil;

2.gil:全域性直譯器鎖,每個執行緒在執行中都需要先獲取gil,保證同一時刻只有乙個執行緒可以執行**;

3. 執行緒釋放gil鎖的情況,在io等操作可能引起阻塞的system call之前,可以暫時釋放gil,執行完畢後必須獲取gil,python3使用計時器執行時間達到閥值時(python2使用tickets記數達到100)當前執行緒釋放gil

4. python多程序可以使用多核的cpu資源

死鎖:

在多執行緒中,執行緒可以通過互斥鎖來保證對同一資源的唯一占有,但當程式變得複雜後,可能會出現執行緒 a 對資源 a 上了鎖,而執行緒 a 後邊需要用到資源 b,使用完畢後才會對資源 a解鎖,而執行緒 b 對資源 b 上了鎖,它後邊選要用到資源 a,用過後才會給 b 解鎖,如果執行緒 a 和執行緒 b 同時執行,就可能會造成一種情況:執行緒 a 在等待執行緒 b 解鎖,執行緒 b 也在等待執行緒 a 解鎖,這就是死鎖問題。

解決方法:​ 死鎖問題應該盡量在設計程式時避免,或新增等待超時時間,從而檢測程式是否產生了死鎖,另一種就是通過銀行家演算法也可以避免死鎖問題

銀行家演算法:​ 銀行家演算法的思想就是,假設銀行有 10 元,這個時候有三個人提出貸款,a 要貸款 9 元,b 要貸款 3 元,c 要貸款 8 元,這時,銀行肯定不夠將所有人都滿足,銀行家演算法就誕生了

​ 這時銀行為了留住所有客戶並且保證自己的錢不會不足,便分批貸款給客戶,先借給 a 2 元、b 2 元、c 4 元,銀行還剩 2 元,此時 b 直需要再借 1 元就滿足了他自己的需求,銀行便借給他 1 元,自己剩 1 元,當 b 用完,將 3 元還給銀行後,銀行再將這 4 元借給 c,c 也就滿足了,等 c 還款後,再將 8 元中的 7 元借給 a,這樣便動態的滿足了三個客戶的需求

​ 銀行家演算法在程式中實際上也是模擬了銀行貸款的過程,作業系統會動態的向各個執行緒分配資源,在分配前,系統會判斷分配後會不會導致系統進入不安全狀態,不會就分配資源給執行緒,會則令執行緒等待

Python多執行緒,併發

單執行緒程式只有乙個 手指 但多執行緒的程式有多個 手指 每個 手指 仍然移動到控制流語句定義的下一行 但這些 手指 可以在程式的不同地方,同時執行不同的 行 你可以使用 python 的threading 模組,在單獨的執行緒中執行延遲或安排的 這個單獨的執行緒將因為 time.sleep 呼叫而...

多執行緒併發總結七 GPU

我們的cpu叫做 處理器可以用來做各種的計算,但是我們現在的計算機如果要處理圖形輸出的話,特別是三維的影象輸出,乙個比較強的gpu是必不可少的。比如一幀的影象的輸出計算,其實針對上面的每乙個畫素是有大量的類似的計算在併發進行著的。而我們的gpu就是設計來專門做這樣的計算的。乙個gpu裡面有很多的計算...

python高階 多執行緒

1.1 獲取執行緒數 import threading import time def fun time.sleep 1 print hello t threading.thread target fun t.start print threading.enumerate while true le...