十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團隊
量身定制 + 運營維護+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
【Python】線程的創(chuàng)建、執(zhí)行、互斥、同步、銷毀
創(chuàng)新互聯(lián)公司主營集安網(wǎng)站建設的網(wǎng)絡公司,主營網(wǎng)站建設方案,APP應用開發(fā),集安h5成都小程序開發(fā)搭建,集安網(wǎng)站營銷推廣歡迎集安等地區(qū)企業(yè)咨詢
還是《【Java】利用synchronized(this)完成線程的臨界區(qū)》(點擊打開鏈接)、《【Linux】線程互斥》(點擊打開鏈接)、《【C++】Windows線程的創(chuàng)建、執(zhí)行、互斥、同步、銷毀》(點擊打開鏈接)中的設置多個線程對一個ticket進行自減操作,用來說明Python中多線程的運用,涉及的創(chuàng)建、執(zhí)行、互斥、同步、銷毀問題。
運行結果如下,還是差不多,運行三次,每次的運行結果,每個線程最終的得票結果是不同的,但是4個線程最終“得票”的總和為 ticket 最初設置的值為100000,證明這4個線程成功實現(xiàn)了互斥。
雖然每次運行結果是不同,但是可以看得出每次運行結果大抵上是平均的。貌似Python對線程作系統(tǒng)資源的處理,比Java要好。
然而,Python總要實現(xiàn)多線程,代碼并不像想象中簡單,具體如下:
[python] view plain copy print?在CODE上查看代碼片派生到我的代碼片
# -*-coding:utf-8-*-
import threading;
mutex_lock = threading.RLock(); # 互斥鎖的聲明
ticket = 100000; # 總票數(shù)
# 用于統(tǒng)計各個線程的得票數(shù)
ticket_for_thread1 = 0;
ticket_for_thread2 = 0;
ticket_for_thread3 = 0;
ticket_for_thread4 = 0;
class myThread(threading.Thread): # 線程處理函數(shù)
def __init__(self, name):
threading.Thread.__init__(self); # 線程類必須的初始化
self.thread_name = name; # 將傳遞過來的name構造到類中的name
def run(self):
# 聲明在類中使用全局變量
global mutex_lock;
global ticket;
global ticket_for_thread1;
global ticket_for_thread2;
global ticket_for_thread3;
global ticket_for_thread4;
while 1:
mutex_lock.acquire(); # 臨界區(qū)開始,互斥的開始
# 僅能有一個線程↓↓↓↓↓↓↓↓↓↓↓↓
if ticket 0:
ticket -= 1;
# 統(tǒng)計哪到線程拿到票
print "%s搶到了票!票還剩余:%d。" % (self.thread_name, ticket);
if self.thread_name == "線程1":
ticket_for_thread1 += 1;
elif self.thread_name == "線程2":
ticket_for_thread2 += 1;
elif self.thread_name == "線程3":
ticket_for_thread3 += 1;
elif self.thread_name == "線程4":
ticket_for_thread4 += 1;
else:
break;
# 僅能有一個線程↑↑↑↑↑↑↑↑↑↑↑↑
mutex_lock.release(); # 臨界區(qū)結束,互斥的結束
mutex_lock.release(); # python在線程死亡的時候,不會清理已存在在線程函數(shù)的互斥鎖,必須程序猿自己主動清理
print "%s被銷毀了!" % (self.thread_name);
# 初始化線程
thread1 = myThread("線程1");
thread2 = myThread("線程2");
thread3 = myThread("線程3");
thread4 = myThread("線程4");
# 開啟線程
thread1.start();
thread2.start();
thread3.start();
thread4.start();
# 等到線程1、2、3、4結束才進行以下的代碼(同步)
thread1.join();
thread2.join();
thread3.join();
thread4.join();
print "票都搶光了,大家都散了吧!";
print "=========得票統(tǒng)計=========";
print "線程1:%d張" % (ticket_for_thread1);
print "線程2:%d張" % (ticket_for_thread2);
print "線程3:%d張" % (ticket_for_thread3);
print "線程4:%d張" % (ticket_for_thread4);
1、從上面的代碼可以看出,在Python2.7中要使用線程必須使用threading而不是古老的thread模塊。
如果你像網(wǎng)上部分遺留依舊的文章一樣,在Python2.7中使用thread來實現(xiàn)線程,至少在Eclipse的Pydev中會報錯:sys.excepthook is missing,lost sys.stderr如下圖所示:
所以必須使用現(xiàn)時Python建議使用的threading。
2、與其它編程語言類似,聲明一個互斥鎖,與一系列的得票數(shù)。之后,與Java同樣地,Python實現(xiàn)線程的函數(shù),是要重寫一個類。而類中使用全局變量,則與同為腳本語言的PHP一樣《【php】global的使用與php的全局變量》(點擊打開鏈接),要用global才能使用這個全局變量,而不是C/C++可以直接使用。
3、需要注意的,Python需要在線程跑完class myThread(threading.Thread)這個類的def run(self)方法之前,必須自己手動清理互斥鎖,它不會像其它編程語言那樣,說線程跑完def run(self)方法,會自然而然地清理該線程被創(chuàng)建的互斥鎖。如果沒有最后一句手動清理互斥鎖,則會造成死鎖。
4、最后與其它編程語言一樣了,利用線程的join方法可以等待這個線程跑完def run(self)方法中的所有代碼,才執(zhí)行之后的代碼,實現(xiàn)同步。否則主函數(shù)中的代碼,相當于與父線程。主函數(shù)開啟的線程,相當于其子線程,互不影響的。
因為name這個變量的作用域只在 make_great這個函數(shù)的范圍內。而不在tt所在的大的函數(shù)范圍內。一旦make_great這個函數(shù)結束了,name這個變量就會被銷毀而傳遞不出makegreat這個函數(shù)。這是為什么第一種情況你得到了none。
因此需要使用return對你想在makegreat函數(shù)局部變量被銷毀之后繼續(xù)使用的變量的值進行拷貝,有點繞666。保存拷貝下來的值不被銷毀,而賦給tt使用。這是為什么要使用return。
Python中有兩個特殊的方法, 一個是構造函數(shù) init , 另一個是析構函數(shù) del ,統(tǒng)稱為魔術方法。
構造函數(shù) init ,創(chuàng)建實例對象之后Python會自動執(zhí)行此方法,把初始化的屬性特點放到實例對象里。
構造函數(shù)是創(chuàng)建并初始對象屬性,那么對象使用完成后,系統(tǒng)是怎么處理這些呢?
這個時候,Python引入了銷毀對象功能的析構函數(shù) del ()
析構函數(shù) del 是對象沒有被引用時會觸發(fā)垃圾回收機制,進行內存釋放.
python 內置的 del 方法稱為析構方法。用于實現(xiàn)對象被銷毀時所需的操作。
常見的應用常見如:
析構方法 del ()是可選的,如果不提供,則Python 會在后臺提供默認析構函數(shù)
如果要顯式的調用析構函數(shù),可以使用del關鍵字: del obj
析構方法的作用是銷毀對象的,在python中采用垃圾回收機制。
Python垃圾回收機制核心思想是:
詳細說明:
我們主動刪除對象調用del 對象;程序運行結束后,python也會自動進行刪除其他的對象。
注意:
如果我們重寫子類的 del () 方法(父類為非 object 的類),則必須顯式調用父類的 del () 方法,這樣才能保證在回收子類對象時,其占用的資源(可能包含繼承自父類的部分資源)能被徹底釋放
我們本期學習了Python內置函數(shù)析構函數(shù),用于沒有被引用的對象進行回收處理,一般情況下,我們不用刻意去調用,python內部會對進行觸發(fā)。
以上是本期內容,歡迎大佬們評論區(qū)指正,下期見~
python函數(shù)調用后的變量不會銷毀,除非程序執(zhí)行完畢,或者手動進行銷毀。