c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划
生活随笔
收集整理的這篇文章主要介紹了
c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
作者 | 萬里羊責編 | 王曉曼出品 | CSDN博客線程和進程計算機的核心是CPU,它承擔了所有的計算任務,就像是一座工廠在時刻運行。如果工廠的資源有限,一次只能供一個車間來使用,也就是說當一個車間開工時其它車間不能工作,也就是一個CPU一次只能執行一個任務。進程就好比工廠的車間,它代表CPU所能處理的單個任務。任一時刻,CPU總是運行一個進程,其他進程處于非運行狀態。當然一個車間還有很多工人,他們互相協同完成一個工作;而線程就好比工廠的工人,一個進程可以包含多個線程。線程(Thread)也叫輕量級進程,是操作系統能夠進行運算調度的最小單位,它被包涵在進程之中,是進程中的實際運作單位。線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。一個線程可以創建和撤消另一個線程,同一進程中的多個線程之間可以并發執行。多線程與多進程通俗易懂的理解就是:
多進程:允許多個任務同時進行
多線程:允許單個任務分成不同的部分運行Python多線程的實現Python3 通過兩個標準庫 thread(python2中是thread模塊)和 threading 提供對線程的支持。thread 提供了低級別的、原始的線程以及一個簡單的鎖,它相比于 threading 模塊的功能還是比較有限的。threading:import?threading?#導入threading庫import?timedef?run(n):
????print("task",?n)
????time.sleep(1)?#延時一秒
????print('2s')
????time.sleep(1)
????print('1s')
????time.sleep(1)
????print('0s')
????time.sleep(1)if?__name__?==?'__main__':
????t1?=?threading.Thread(target=run,?args=("t1",))#創建線程1,取名為t1
????t2?=?threading.Thread(target=run,?args=("t2",))#創建線程2,取名為t2
????t1.start()?#開啟線程t1
????t2.start()?#開啟線程t2輸出結果:task?t1
task?t22s2s1s1s0s0s可以看出先開啟了線程t1,在開啟t2然后每隔一秒打印數據。自定義線程通過繼承threading.Thread來自定義線程類,其本質是重構Thread類中的run方法:import?threadingimport?timeclass?MyThread(threading.Thread):def?__init__(self,?n):
????????super(MyThread,?self).__init__()??#?重構run函數必須要寫
????????self.n?=?ndef?run(self):
????????print("task",?self.n)
????????time.sleep(1)
????????print('2s')
????????time.sleep(1)
????????print('1s')
????????time.sleep(1)
????????print('0s')
????????time.sleep(1)if?__name__?==?"__main__":
????t1?=?MyThread("t1")
????t2?=?MyThread("t2")
????t1.start()
????t2.start()輸出結果:task?t1
task?t22s2s1s1s0s0s守護線程?下面這個例子,使用setDaemon(True)把所有的子線程都變成了主線程的守護線程,因此當主進程結束后,子線程也會隨之結束。所以當主線程結束后,整個程序就退出了。import?threadingimport?timedef?run(n):
????print("task",?n)
????time.sleep(1)???????#此時子線程停1s
????print('3')
????time.sleep(1)
????print('2')
????time.sleep(1)
????print('1')if?__name__?==?'__main__':
????t?=?threading.Thread(target=run,?args=("t1",))
????t.setDaemon(True)???#把子進程設置為守護線程,必須在start()之前設置
????t.start()
????print("end")輸出結果:task?t1
end可以看到,t1線程并沒有執行完畢,而是直接結束了。說明設置子線程為守護線程之后,主線程結束了,子線程也立即結束不再執行。程序中不是只創建了一個線程么?怎么會有主線程和子線程呢?其實呢程序運行時就會創建一個線程,而這個線程就是主線程。主線程等待子線程運行結束import?threadingimport?timedef?run(n):
????print("task",?n)
????time.sleep(1)??????
????print('3')
????time.sleep(1)
????print('2')
????time.sleep(1)
????print('1')if?__name__?==?'__main__':
????t?=?threading.Thread(target=run,?args=("t1",))
????t.setDaemon(True)???#把子進程設置為守護線程,必須在start()之前設置
????t.start()
????t.join()?#?設置主線程等待子線程結束
????print("end")輸出結果:task?t1321
end運行.join()后的程序表明等待所有線程結束以后再進行.join()之后的操作結合以上代碼就是,等待t1結束以后再執行end。多線程共享全局變量線程是進程的執行單元,進程是系統分配資源的最小單位,所以在同一個進程中的多線程是共享資源的。那么共享資源時就需要用到全局變量。import?threadingimport?time
num?=?100def?work1():global?numfor?i?in?range(3):
????????num?+=?1
????print("in?work1?num?is?:?%d"?%?num)def?work2():global?num
????print("in?work2?num?is?:?%d"?%?num)if?__name__?==?'__main__':
????t1?=?threading.Thread(target=work1)
????t1.start()
????time.sleep(1)
????t2?=?threading.Thread(target=work2)
????t2.start()運行結果如下:in?work1?num?is?:?103in?work2?num?is?:?103可以看到兩者輸出的結果是相同的,說明是可以共享全局變量的。互斥鎖由于線程之間是進行隨機調度,并且每個線程可能只執行n條,當多個線程同時修改同一條數據時可能會出現臟數據,因而,出現了線程鎖,即同一時刻只允許一個線程執行操作。線程鎖用于鎖定資源,可以定義多個鎖, 在下面的實例中, 當你需要獨占某一資源時,任何一個鎖都可以鎖這個資源,就好比你用不同的鎖都可以把相同的一個門鎖住是一個道理。由于線程之間是進行隨機調度,如果有多個線程同時操作一個對象,如果沒有很好地保護該對象,會造成程序結果的不可預期,我們也稱此為“線程不安全”。為了方式上面情況的發生,就出現了互斥鎖(Lock):import?threading
def?work1():global?A,lock#定義A和lock為全局變量lock.acquire()#上鎖for?i?in?range(5):
????????A+=1
????????print('work1',A)lock.release()#解鎖def?work2():global?A,locklock.acquire()for?i?in?range(5):
????????A+=10
????????print('work2',A)lock.release()if?__name__=='__main__':lock=threading.Lock()#定義鎖
????A=0
????t1=threading.Thread(target=work1)
????t2=threading.Thread(target=work2)
????t1.start()
????t2.start()
????t1.join()
????t2.join()輸出結果:work1?1
work1?2
work1?3
work1?4
work1?5
work2?15
work2?25
work2?35
work2?45
work2?55可以發現對兩組數據是沒有影響的,感興趣的可以嘗試一下不加鎖會有什么情況。遞歸鎖RLcok類的用法和Lock類一模一樣,但它支持嵌套,在多個鎖沒有釋放的時候一般會使用RLcok類。import?threading
import?time
def?Func(lock):global?gl_numlock.acquire()
????gl_num?+=?1
????time.sleep(1)
????print(gl_num)lock.release()if?__name__?==?'__main__':
????gl_num?=?0lock?=?threading.RLock()for?i?in?range(10):
????????t?=?threading.Thread(target=Func,?args=(lock,))
????????t.start()輸出結果:1
2
3
4
5
6
7
8
9
10信號量(BoundedSemaphore類)互斥鎖同時只允許一個線程更改數據,而Semaphore是同時允許一定數量的線程更改數據,比如廁所有3個坑,那最多只允許3個人上廁所,后面的人只能等里面有人出來了才能再進去。實際中博主還沒有用到過,所以理解不是特別透徹。import?threadingimport?timedef?run(n,?semaphore):
????semaphore.acquire()???#加鎖
????time.sleep(1)
????print("run?the?thread:%s\n"?%?n)
????semaphore.release()?????#釋放if?__name__?==?'__main__':
????num?=?0
????semaphore?=?threading.BoundedSemaphore(5)??#?最多允許5個線程同時運行for?i?in?range(22):
????????t?=?threading.Thread(target=run,?args=("t-%s"?%?i,?semaphore))
????????t.start()while?threading.active_count()?!=?1:pass??#?print?threading.active_count()else:
????????print('-----all?threads?done-----')輸出結果有點長,就不貼輸出結果了。事件(Event類)python線程的事件用于主線程控制其他線程的執行,事件是一個簡單的線程同步對象,其主要提供以下幾個方法:- clear 將flag設置為“False”;
- set 將flag設置為“True”;
- is_set 判斷是否設置了flag;
- wait 會一直監聽flag,如果沒有檢測到flag就一直處于阻塞狀態。
import?threadingimport?time
event?=?threading.Event()def?lighter():
????count?=?0
????event.set()?????#初始值為綠燈while?True:if?5?10?:
????????????event.clear()??#?紅燈,清除標志位
????????????print("1mred?light?is?on...")elif?count?>?10:
????????????event.set()??#?綠燈,設置標志位
????????????count?=?0else:
????????????print("mgreen?light?is?on...")
????????time.sleep(1)
????????count?+=?1def?car(name):while?True:if?event.is_set():??????#判斷是否設置了標志位
????????????print("[%s]?running..."%name)
????????????time.sleep(1)else:
????????????print("[%s]?sees?red?light,waiting..."%name)
????????????event.wait()
????????????print("[%s]?green?light?is?on,start?going..."%name)
light?=?threading.Thread(target=lighter,)
light.start()
car?=?threading.Thread(target=car,args=("MINI",))
car.start()這段代碼模擬紅綠燈,很形象。Qthread本以為我學完了多線程就完事了,就可以將語音和QT界面進行整合了。當我去實現的時候發現問題不是這么簡單,通過語音控制打開一個特定的界面可以實現,但是為什么只要這個特定的界面關閉了,我語音的線程也就結束了。困惑了我好久,最后終于在某社區發現了答案!原來QT自帶的有Qthread,當多線程涉及到界面交互時最好用Qthread來實現。然后又查閱大量博客,看了大量代碼。在使用繼承QThread的run方法之前需要了解一條規則:QThread只有run函數是在新線程里的,其他所有函數都在QThread生成的線程里- QThread只有run函數是在新線程里的;
- QThread只有run函數是在新線程里的;
- QThread只有run函數是在新線程里的。
#coding=utf-8
import?sys
from?PyQt5.QtGui?import?*
from?PyQt5.QtWidgets?import?*
from?PyQt5.QtCore?import?*
count?=?0#?工作線程class?WorkThread(QThread):#?pyqtSignal是信號類
????timeout?=?pyqtSignal()??#?每隔一秒發送一個信號end?=?pyqtSignal()??#?計數完成后發送一個信號def?run(self):while?True:#?休眠1秒self.sleep(1)if?count?==?5:self.end.emit()??#?發送end信號,調用和end信號關聯的方法breakself.timeout.emit()??#?發送timeout信號class?Counter(QWidget):def?__init__(self):super(Counter,?self).__init__()self.setWindowTitle("用QThread編寫計數器")self.resize(600,?400)
????????layout?=?QVBoxLayout()#?QLCDNumber?用于模擬LED顯示效果,類似于Labelself.lcdNumber?=?QLCDNumber()
????????layout.addWidget(self.lcdNumber)
????????button?=?QPushButton("開始計數")
????????layout.addWidget(button)self.workThread?=?WorkThread()self.workThread.timeout.connect(self.countTime)self.workThread.end.connect(self.end)
????????button.clicked.connect(self.work)self.setLayout(layout)def?countTime(self):
????????global?count
????????count?+=?1self.lcdNumber.display(count)def?end(self):
????????QMessageBox.information(self,?'消息',?'計數結束',?QMessageBox.Ok)
????????global?count
????????count?=0def?work(self):self.workThread.start()if?__name__?==?"__main__":
????app?=?QApplication(sys.argv)
????main?=?Counter()
????main.show()
????sys.exit(app.exec_())點擊開始計時就會出現類似LCD的顯示,計時到5秒結束后彈窗提醒。運行結果如下:通過這個例程讓我對Qthread有了更好的理解,經管理解的不是特別透徹但是我知道怎么來改出來我想用的代碼。之前提到的打開窗口線程阻塞,關閉窗口線程重啟,其實這個計時器是一個很好的例子,但是關于線程阻塞.wait不好使。我的方法是定義一個全局變量mode=0(用來判斷是否需要阻塞線程),如果窗口打開后那么給這個全局賦值mode=1,在run函數里對這個mode進行判斷,如果mode等于1那么可以用一個循環來延時實現。if?mode:while(mode):self.sleep(1)當窗口關閉以后給mode 賦值等于0通過這種方法可以實現,很多小伙伴又會問怎么判斷窗口打開和關閉,其實在自己寫的窗口函數最前面加mode=1和最后面mode=0就可以了不用進行判斷。版權聲明:本文為CSDN博主「萬里羊」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。原文鏈接:https://blog.csdn.net/weixin_44895651/article/details/105877358更多精彩推薦
?那些被大數據時代拋棄的人
?反轉!物聯網火爆,開發者卻太難了!
?小米回應林斌退休傳聞;哈工大等高校被禁止使用 MATLAB;統信軟件 UOS20 SP1 系統升級| 極客頭條
?一篇與眾不同的 String、StringBuilder 和 StringBuffer 詳解
?利用 AssemblyAI 在 PyTorch 中建立端到端的語音識別模型
?贈書 | 供應鏈金融模式有哪些?區塊鏈在供應鏈金融中如何應用?
你點的每個“在看”,我都認真當成了喜歡
總結
以上是生活随笔為你收集整理的c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 9开启线程日志_GC 日志分析
- 下一篇: 查看显卡显存_强力散热别浪费 显卡超频这