python等待線程結束
⑴ Python多線程編程之線程結束
線程管理包括線程創建、線程啟動、線程休眠、等待線程結束和線程停止。線程創建、線程啟動、線程休眠前文已提到過,這里不再贅述。
1 等待線程結束等待線程結束使用的是join()方法,當前線程調用t1線程的join()方法時則阻塞當前進程,等待t1線程結束。如果t1線程結束或等待超時,則當前線程回到活動狀態繼續執行。join()方法語法如下:
join(timeout=None)參數timeout是設置超時時間,單位是s。如果沒有設置timeout,則可以一直等待
當一個線程依賴於另一個線程的運行結果時,就可以調用另一個線程的join()方法等待它運行完成
example:
_value=0defthread_body():globalshared_valueprint('ThreadA開始......')for_inrange(5):print('ThreadA執行中......')shared_value+=1time.sleep(1)print('ThreadA結束......')defmain():print('主線程開始......')t1=threading.Thread(target=thread_body,name='ThreadA')t1.start()print('主線程被阻塞......')t1.join()print(f'value={shared_value}')print('主線程繼續執行......')result:
主線程開始......ThreadA開始......主線程被阻塞......ThreadA執行中......ThreadA執行中......ThreadA執行中......ThreadA執行中......ThreadA執行中......ThreadA結束......value=5主線程繼續執行......這里設置了一個共享變數shared_value,線程主體中對該變數進行了修改。在主函數裡面調用了t1的join()方法,就會導致主線程阻塞,等待線程t1執行結束,主線程才會繼續執行。從結果來看,主線程缺失被阻塞了,列印出來的shared_value的值已經由0變成5了
2 線程停止對於有些復雜業務,需要設置一個線程停止變數來決定線程停止。例如,有一個抓取數據的系統,每隔半小時獲取執行一次數據抓取任務。數據抓取任務一般在子線程中進行,休眠一段時間再執行。這個子線程中國會有一個死循環。為了能停止子線程,應設置一個線程停止變數
example:
importthreadingimporttimeis_running=Truedefthread_body():whileis_running:print('ThreadA開始......')#數據抓取任務print('ThreadA執行中......')time.sleep(1)print('ThreadA結束......')print('整個程序執行完成')defmain():print('主線程開始......')t1=threading.Thread(target=thread_body)t1.start()command=input('請輸入停止指令:')ifcommand=='exit':globalis_runningis_running=Falseif__name__=='__main__':main()result:
主線程開始......ThreadA開始......ThreadA執行中......請輸入停止指令:exitThreadA結束......整個程序執行完成這里設置了一個線程停止變數is_running,默認值為True.當用戶通過鍵盤在控制台輸入exit時,其值變為False,然後程序終止。需要注意的是,控制台輸入exit後,還需要按enter鍵才可以。
⑵ Python中threading的join和setDaemon的區別及用法
Python多線程編程時經常會用到join()和setDaemon()方法,基本用法如下:
join([time]): 等待至線程中止。這阻塞調用線程直至線程的join() 方法被調用中止-正常退出或者拋出未處理的異常-或者是可選的超時發生。
setDaemon,將該線程標記為守護線程或用戶線程
1、join ()方法:主線程A中,創建了子線程B,並且在主線程A中調用了B.join(),那麼,主線程A會在調用的地方等待,直到子線程B完成操作後,才可以接著往下執行,那麼在調用這個線程時可以使用被調用線程的join方法。
原型:join([timeout]),裡面的參數時可選的,代表線程運行的最大時間,即如果超過這個時間,不管這個此線程有沒有執行完畢都會被回收,然後主線程或函數都會接著執行的。
import threadingimport time class MyThread(threading.Thread): def __init__(self, id): threading.Thread.__init__(self) self.id = id def run(self): x = 0 time.sleep(10) print(self.id) print('線程結束:'+str(time.time())) if __name__ == "__main__": t1 = MyThread(999) print('線程開始:'+str(time.time())) t1.start() print('主線程列印開始:'+str(time.time())) for i in range(5): print(i) time.sleep(2) print('主線程列印結束:' + str(time.time()))
線程開始:1497534590.2784667
主線程列印開始:1497534590.2794669
0
1
2
3
4
主線程列印結束:1497534592.279581
999
線程結束:1497534600.2800388
從列印結果可知,線程t1 start後,主線程並沒有等線程t1運行結束後再執行,而是在線程執行的同時,執行了後面的語句。
現在,把join()方法加到啟動線程後面(其他代碼不變)
import threadingimport time class MyThread(threading.Thread): def __init__(self, id): threading.Thread.__init__(self) self.id = id def run(self): x = 0 time.sleep(10) print(self.id) print('線程結束:'+str(time.time())) if __name__ == "__main__": t1 = MyThread(999) print('線程開始:'+str(time.time())) t1.start() t1.join() print('主線程列印開始:'+str(time.time())) for i in range(5): print(i) time.sleep(2) print('主線程列印結束:' + str(time.time()))
線程開始:1497535176.5019968
999
線程結束:1497535186.5025687
主線程列印開始:1497535186.5025687
0
1
2
3
4
主線程列印結束:1497535188.5026832
線程t1 start後,主線程停在了join()方法處,等子線程t1結束後,主線程繼續執行join後面的語句。
2、setDaemon()方法。主線程A中,創建了子線程B,並且在主線程A中調用了B.setDaemon(),這個的意思是,把主線程A設置為守護線程,這時候,要是主線程A執行結束了,就不管子線程B是否完成,一並和主線程A退出.這就是setDaemon方法的含義,這基本和join是相反的。此外,還有個要特別注意的:必須在start() 方法調用之前設置。import threading
import time class MyThread(threading.Thread): def __init__(self, id): threading.Thread.__init__(self) self.id = id def run(self): x = 0 time.sleep(10) print(self.id) print("This is:" + self.getName()) # 獲取線程名稱 print('線程結束:' + str(time.time())) if __name__ == "__main__": t1 = MyThread(999) print('線程開始:'+str(time.time())) t1.setDaemon(True) t1.start() print('主線程列印開始:'+str(time.time())) for i in range(5): print(i) time.sleep(2) print('主線程列印結束:' + str(time.time()))
線程開始:1497536678.8509264
主線程列印開始:1497536678.8509264
0
1
2
3
4
主線程列印結束:1497536680.8510408
t1.setDaemon(True)的操作,將子線程設置為了守護線程。根據setDaemon()方法的含義,父線程列印內容後便結束了,不管子線程是否執行完畢了。
如果在線程啟動前沒有加t1.setDaemon(True),輸出結果為:
線程開始:1497536865.3215919
主線程列印開始:1497536865.3215919
0
1
2
3
4
主線程列印結束:1497536867.3217063
999
This is:Thread-1
線程結束:1497536875.3221638
程序運行中,執行一個主線程,如果主線程又創建一個子線程,主線程和子線程就分兵兩路,分別運行,那麼當主線程完成想退出時,會檢驗子線程是否完成,如果子線程未完成,則主線程會等待子線程完成後再退出;
有時我們需要的是,子線程運行完,才繼續運行主線程,這時就可以用join方法(在線程啟動後面);
但是有時候我們需要的是,只要主線程完成了,不管子線程是否完成,都要和主線程一起退出,這時就可以用setDaemon方法(在線程啟動前面)。
⑶ Python中Thread類的start和run方法的區別
1) start 方法:在 Python 中,通過調用 Thread 類的 start() 方法來啟動線程。這個方法會立即觸發新線程的創建並使其進入可運行狀態。一旦線程獲得 CPU 時間,它就會開始執行 run() 方法。run() 方法定義了線程的執行行為,是線程生命周期中的主體。當 run() 方法執行完成後,線程即結束。
2) run 方法:相比之下,run() 方法是一個普通的方法,如果在主線程中直接調用它,程序的執行流程將不會改變,仍然遵循順序執行的原則,即必須等待 run() 方法執行完畢後,程序才會繼續執行後續代碼。這種調用方式沒有實現多線程的並行處理。
總結:要實現真正的多線程,應使用 start() 方法來啟動線程。run() 方法僅作為線程的一個普通行為,會在啟動線程時自動執行,這是由 Java 虛擬機(JVM)的內存管理機制所決定的。run() 方法必須被聲明為 public,並且沒有返回值。