當前位置:
首頁 > 最新 > Python的Socket知識6:線程、線程鎖、線程池、上下文管理

Python的Socket知識6:線程、線程鎖、線程池、上下文管理

1、進程、線程

進程(process)是cpu資源分配的最小單位,線程(thread)是cpu調度的最小單位。多線程和多進程的應用目的是為了提高並發。一個應用程序可以包含多個進程,而一個進程又可以包含多個線程。默認一個應用程序是單進程、單線程。

1)什麼是進程(process)

進程:指在系統中能獨立運行並作為資源分配的基本單位,它是由一組機器指令、數據和堆棧等組成的,是一個能獨立運行的活動實體。每一個進程都有一個自己的地址空間,即進程空間或(虛空間)。進程空間的大小隻與處理機的位數有關,一個 16 位長處理機的進程空間大小為 216 ,而 32 位處理機的進程空間大小為 232 。進程至少有 5 種基本狀態,它們是:初始態,執行態,等待狀態,就緒狀態,終止狀態。比如打開一個QQ算是一個進程。

2)什麼是線程(thread)

線程,在網路或多用戶環境下,一個伺服器通常需要接收大量且不確定數量用戶的並發請求,為每一個請求都創建一個進程顯然是行不通的,無論是從系統資源開銷方面或是響應用戶請求的效率方面來看。因此,操作系統中線程的概念便被引進了。線程,是進程的一部分,一個沒有線程的進程可以被看作是單線程的。線程有時又被稱為輕量級進程,也是CPU 調度的一個基本單位。

3)進程和線程的區別:

4)python中關於線程和進程的使用經驗:

5)創建線程

threading提供了一個比thread模塊更高層的API來提供線程的並發性

創建線程的基本方法有兩種:

1)利用threading.Thread創建對象,在它的初始化函數(__init__)中將可調用對象作為參數傳入。

案例1:創建一個子線程,但子線程什麼時候被執行,需要服從系統的調用。

雖然代碼解釋到了t.start(),但實際執行時間取決於系統。

importtime

#定義一個主線程

deff1(i):

time.sleep(3)# 需要3秒執行完畢

print(i)

#創建的子線程

importthreading

#寫完下面一句,就代表創建線程完畢

#target是需要執行的函數,args是傳入函數的參數

t=threading.Thread(target=f1,args=(123,))

#執行子線程

t.start()#執行時間待定

#執行主線程

f1(456)

print("end")

執行結果:

案例2:使用setDaemon(True)控制主線程不等子線程。

setDaemon()方法。當參數為True時,把主線程設置為守護線程,主線程A執行結束了,就不管子線程是否完成,一併和主線程退出,也即主線程不等子線程。此方法必須在start() 方法調用之前設置,如果不設置為守護線程,程序會被無限掛起。

importtime

#定義一個主線程

deff1(i):

time.sleep(3)# 需要3秒執行完畢

print(i)

#創建的子線程

importthreading

#寫完下面一句,就代表創建線程完畢

#target是需要執行的函數,args是傳入函數的參數

t=threading.Thread(target=f1,args=(123,))

#True表示主線程不等子線程,主線程結束則程序結束。

t.setDaemon(True)

#執行子線程

t.start()#執行時間待定

#執行主線程

f1(456)

print("end")

效果:

案例3:join的參數使用,控制主線程等待子線程多長時間

當一個線程操作需要等待另一個線程執行完畢之後才能繼續進行時,使用Join()方法。Join方法會等到使用該方法的線程結束後再執行下面的代碼。

importtime

#定義一個主線程

deff1(i):

time.sleep(3)# 需要3秒執行完畢

print(i)

#創建的子線程

importthreading

#寫完下面一句,就代表創建線程完畢

#target是需要執行的函數,args是傳入函數的參數

t=threading.Thread(target=f1,args=(123,))

#True表示主線程不等子線程,主線程結束則程序結束。

t.setDaemon(True)

#執行子線程

t.start()#執行時間待定

#主線程執行到join時,等待,直到子線程執行完畢,再繼續執行join後的程序

t.join(2)#2表示最多等2秒

print("end")

print("end")

效果:

假設join中的秒數大一點,可能就會有子線程執行完畢

t.join(4)#2表示最多等4秒

2)第二種創建方式,自定義類,通過繼承Thread類,重寫它的run方法

案例4:自定義線程的使用

#自定義f2方法

deff2(arg):

print(arg)

#創建線程

importthreading

classmythread(threading.Thread):#繼承threading.Thread方法

def__init__(self,func,args):

self.func=func

self.args=args

# 執行父類的構造方法

super(mythread,self).__init__()

defrun(self):

self.func(self.args)

#實例化線程

obj=mythread(f2,123)

#執行線程

obj.start()

threading.Thread類的使用方法:

2、線程鎖,解決數據共享

同一時刻允許一個線程執行操作。由於線程調用隨機,當多個線程都要去修改某一個共享數據的時候,需要對數據訪問進行同步。

假設兩個線程對象t1和t2都要對num=0進行增1運算,t1和t2都各對num修改10次,num的最終的結果應該為20。但是由於是多線程訪問,有可能出現下面情況:在num=0時,t1取得num=0。系統此時把t1調度為」sleeping」狀態,把t2轉換為」running」狀態,t2頁獲得num=0。然後t2對得到的值進行加1並賦給num,使得num=1。然後系統又把t2調度為」sleeping」,把t1轉為」running」。線程t1又把它之前得到的0加1後賦值給num。這樣,明明t1和t2都完成了1次加1工作,但結果仍然是num=1。

threading.Lock類對象,在run方法里,使用lock.acquire()獲得了這個鎖。此時,其他的線程就無法再獲得該鎖了,他們就會阻塞在「if lock.acquire()」這裡,直到鎖被另一個線程釋放:lock.release()。

案例5:使用threading.Lock(),上一把鎖。

執行結果如下:

案例6:使用threading.RLock(),上多把鎖。

執行效果:

3、信號量(Semaphore):批量放行

互斥鎖是同時只允許一個線程更改數據,而Semaphore是同時允許一定數量的線程更改數據,比如廁所有三個坑,最多只允許三個人同時上廁所,後面的人只能等裡面有人出來才能再進去。

案例7:Semaphore批量放行,同時允許5個人同時修改。

執行效果:

5、事件(Event):全部放行或擋住。

python線程的事件用於主線程式控制制其他線程的執行。事件提供了三個方法set、wait、clear。事件處理的機制,全局定義了一個「Flag」值為False,那麼當程序執行evevt.wait方法時,就會阻塞,如果「Flag」值為True,那麼event.wait方法時便不再阻塞。

clear:將Flag設置為False,set:將Flag設置為True

案例8:事件event,全部擋住或放行,按照代碼從上到下的執行原則,可以寫出其執行順序。

執行結果:

6、條件:使得線程等待,只有滿足某條件時,才釋放n個線程。

案例9:條件,直接條用condition。

案例10:自己寫條件,使用wait_for獲取

效果:

7、線程池。

Python標準庫為我們提供了threading和multiprocessing模塊編寫相應的多線程/多進程代碼,但是當項目達到一定的規模,頻繁創建/銷毀進程或者線程是非常消耗資源的,這個時候我們就要編寫自己的線程池/進程池,以空間換時間。

線程池需要實現的功能:

案例11:使用隊列自定義線程池,線程池中放的線程,但是線程不能重複利用

案例12:自定義線程池,在線程池中放任務,線程池的任務存放是用列表的形式,任務有兩種類型,一種是實際的任務,一種是在尾部放幾個空的任務,空的任務作用是用於識別任務執行結束。

執行結果:列印0-29

8、上下文管理

contextlib模塊的contextmanager裝飾器可以更方便的實現上下文管理器。任何能夠被yield關鍵詞分割成兩部分的函數,都能夠通過裝飾器裝飾的上下文管理器來實現。任何在yield之前的內容都可以看做在代碼塊執行前的操作,而任何yield之後的操作都可以放在finally函數中。

案例13:上下文管理案例,看執行順序

執行結果:

案例14:利用上下文管理,實現socket自動關閉

執行效果:


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python 的精彩文章:

為什麼程序員要學Python?
Python-GUI Tkinter模塊

TAG:Python |