Python線程同步的實現(xiàn)代碼
本文介紹Python中的線程同步對象,主要涉及 thread 和 threading 模塊。
threading 模塊提供的線程同步原語包括:Lock、RLock、Condition、Event、Semaphore等對象。
線程執(zhí)行
join與setDaemon
子線程在主線程運行結(jié)束后,會繼續(xù)執(zhí)行完,如果給子線程設置為守護線程(setDaemon=True),主線程運行結(jié)束子線程即結(jié)束;
如果join()線程,那么主線程會等待子線程執(zhí)行完再執(zhí)行。
import threading
import time
def get_thread_a():
print("get thread A started")
time.sleep(3)
print("get thread A end")
def get_thread_b():
print("get thread B started")
time.sleep(5)
print("get thread B end")
if __name__ == "__main__":
thread_a = threading.Thread(target=get_thread_a)
thread_b = threading.Thread(target=get_thread_b)
start_time = time.time()
thread_b.setDaemon(True)
thread_a.start()
thread_b.start()
thread_a.join()
end_time = time.time()
print("execution time: {}".format(end_time - start_time))
thread_a是join,首先子線程thread_a執(zhí)行,thread_b是守護線程,當主線程執(zhí)行完后,thread_b不會再執(zhí)行執(zhí)行結(jié)果如下:
get thread A started
get thread B started
get thread A end
execution time: 3.003199815750122
線程同步
當線程間共享全局變量,多個線程對該變量執(zhí)行不同的操作時,該變量最終的結(jié)果可能是不確定的(每次線程執(zhí)行后的結(jié)果不同),如:對count變量執(zhí)行加減操作 ,count的值是不確定的,要想count的值是一個確定的需對線程執(zhí)行的代碼段加鎖。
python對線程加鎖主要有Lock和Rlock模塊
Lock:
from threading import Lock lock = Lock() lock.acquire() lock.release()
Lock有acquire()和release()方法,這兩個方法必須是成對出現(xiàn)的,acquire()后面必須release()后才能再acquire(),否則會造成死鎖
Rlock:
鑒于Lock可能會造成死鎖的情況,RLock(可重入鎖)對Lock進行了改進,RLock可以在同一個線程里面連續(xù)調(diào)用多次acquire(),但必須再執(zhí)行相同次數(shù)的release()
from threading import RLock lock = RLock() lock.acquire() lock.acquire() lock.release() lock.release()
condition(條件變量),線程在執(zhí)行時,當滿足了特定的條件后,才可以訪問相關的數(shù)據(jù)
import threading
def get_thread_a(condition):
with condition:
condition.wait()
print("A : Hello B,that's ok")
condition.notify()
condition.wait()
print("A : I'm fine,and you?")
condition.notify()
condition.wait()
print("A : Nice to meet you")
condition.notify()
condition.wait()
print("A : That's all for today")
condition.notify()
def get_thread_b(condition):
with condition:
print("B : Hi A, Let's start the conversation")
condition.notify()
condition.wait()
print("B : How are you")
condition.notify()
condition.wait()
print("B : I'm fine too")
condition.notify()
condition.wait()
print("B : Nice to meet you,too")
condition.notify()
condition.wait()
print("B : Oh,goodbye")
if __name__ == "__main__":
condition = threading.Condition()
thread_a = threading.Thread(target=get_thread_a, args=(condition,))
thread_b = threading.Thread(target=get_thread_b, args=(condition,))
thread_a.start()
thread_b.start()
Condition內(nèi)部有一把鎖,默認是RLock,在調(diào)用wait()和notify()之前必須先調(diào)用acquire()獲取這個鎖,才能繼續(xù)執(zhí)行;當wait()和notify()執(zhí)行完后,需調(diào)用release()釋放這個鎖,在執(zhí)行with condition時,會先執(zhí)行acquire(),with結(jié)束時,執(zhí)行了release();所以condition有兩層鎖,最底層鎖在調(diào)用wait()時會釋放,同時會加一把鎖到等待隊列,等待notify()喚醒釋放鎖
wait() :允許等待某個條件變量的通知,notify()可喚醒
notify(): 喚醒等待隊列wait()
執(zhí)行結(jié)果:
B : Hi A, Let's start the conversation
A : Hello B,that's ok
B : How are you
A : I'm fine,and you?
B : I'm fine too
A : Nice to meet you
B : Nice to meet you,too
A : That's all for today
B : Oh,goodbye
Semaphore(信號量)
用于控制線程的并發(fā)數(shù),如爬蟲中請求次數(shù)過于頻繁會被禁止ip,每次控制爬取網(wǎng)頁的線程數(shù)量可在一定程度上防止ip被禁;文件讀寫中,控制寫線程每次只有一個,讀線程可多個。
import time
import threading
def get_thread_a(semaphore,i):
time.sleep(1)
print("get thread : {}".format(i))
semaphore.release()
def get_thread_b(semaphore):
for i in range(10):
semaphore.acquire()
thread_a = threading.Thread(target=get_thread_a, args=(semaphore,i))
thread_a.start()
if __name__ == "__main__":
semaphore = threading.Semaphore(2)
thread_b = threading.Thread(target=get_thread_b, args=(semaphore,))
thread_b.start()
上述示例了每隔1秒并發(fā)兩個線程執(zhí)行的情況,當調(diào)用一次semaphore.acquire()時,Semaphore的數(shù)量就減1,直至Semaphore數(shù)量為0時被鎖上,當release()后Semaphore數(shù)量加1。Semaphore在本質(zhì)上是調(diào)用的Condition,semaphore.acquire()在Semaphore的值為0的條件下會調(diào)用Condition.wait(), 否則將值減1,semaphore.release()會將Semaphore的值加1,并調(diào)用Condition.notify()
Semaphore源碼
def acquire(self, blocking=True, timeout=None):
if not blocking and timeout is not None:
raise ValueError("can't specify timeout for non-blocking acquire")
rc = False
endtime = None
with self._cond:
while self._value == 0:
if not blocking:
break
if timeout is not None:
if endtime is None:
endtime = _time() + timeout
else:
timeout = endtime - _time()
if timeout <= 0:
break
self._cond.wait(timeout)
else:
self._value -= 1
rc = True
return rc
def release(self):
with self._cond:
self._value += 1
self._cond.notify()
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Anaconda+pycharm安裝及環(huán)境配置全過程
在使用pyCharm進行開發(fā)時,需要用到Anaconda創(chuàng)建的環(huán)境,下面這篇文章主要給大家介紹了關于Anaconda+pycharm安裝及環(huán)境配置的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-09-09
對Python的交互模式和直接運行.py文件的區(qū)別詳解
今天小編就為大家分享一篇對Python的交互模式和直接運行.py文件的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06
提升Python項目整潔度使用import?linter實例探究
在復雜的Python項目中,良好的代碼組織結(jié)構(gòu)是維護性和可讀性的關鍵,本文將深入研究?import-linter?工具,它是一個強大的靜態(tài)分析工具,旨在優(yōu)化項目的模塊導入,提高代碼質(zhì)量和可維護性2024-01-01
windows下 兼容Python2和Python3的解決方法
這篇文章主要介紹了windows下 兼容Python2和Python3的解決方法,需要的朋友可以參考下2018-12-12
如何用VScode配置Python開發(fā)環(huán)境
這篇文章主要介紹了如何用VScode配置Python開發(fā)環(huán)境,vscode有很多優(yōu)點,用VScode來編寫Python,也是相當?shù)暮糜玫?需要的朋友可以參考下2023-03-03

