多執行緒
- 導讀
- 專案中多執行緒的目的
- 實戰操作
- 小知識
- 創建一個簡單的執行緒
- 守護執行緒
- 主行程等待子行程結束
- 共享全域變數的特性
- 鎖
- 互斥鎖
- 信號量
- 送點資源
導讀

隨著暑假的推進,手把手教你做專案前邊的準備也差不多了后續的專案也漸漸要開始了但是正式發出來可能要等一段時間前后端都是我一個人確實有點費力(畢竟我也是菜雞),后面我在想想怎么提速吧嘻嘻 😃 詳情請大家關注請大家關注手把手教你做專案專欄里面有更多資源等你來探索哦,好了我們今天我們照常學習新知識為以后的專案做鋪墊,老規矩喊出我們的口號:“不肥身體,肥學問”來吧開始,
專案中多執行緒的目的
具體原理我覺得這應該是可以跳到作業系統里面了一點點小小總結大家還可以找本作業系統的書看看,老規矩找不到的話找我主頁,有一個關于資源的文章里面有資源當然也可以私信我,
我們再說說我們專案里面用多執行緒的目的:
1.執行緒之間共享記憶體非常容易,
2·使用多執行緒來實作多任務并發執行比使用多行程的效率高
3·有時候可以節省運行時間,這個一會在下面就會知道
4·當你一個檔案要同時執行多個功能時就可以用到多執行緒
python語言內置了多執行緒功能支持,而不是單純地作為底層作業系統的調度方式,從而簡化了python的多執行緒編程,
實戰操作
說這么多不如實際動手練練,首先匯入執行緒
特別注意:大家在見建檔案的時候名字千萬別和匯入的包threading一樣不然會出錯的,
小知識
import threading
讓我們先看看自己程式現在有多少個行程
import threading
def main():
print(threading.current_thread())
if __name__ == '__main__':
main()
結果:1#我的就一個你的呢?
如果你的行程不為一的話還可以這樣查看每一個行程名
import threading
def main():
print(threading.active_count())
print(threading.enumerate())
if __name__ == '__main__':
main()
>>>[<_MainThread(MainThread, started 36004)>]#回傳的是一個串列因為我的目前就一個所以就一個主行程
還可以查看正在運行的行程
import threading
def main():
print(threading.active_count())
print(threading.enumerate())
print(threading.current_thread())
if __name__ == '__main__':
main()
>1
[<_MainThread(MainThread, started 36004)>]
<_MainThread(MainThread, started 36004)>
創建一個簡單的執行緒
首先我們先介紹一下threading.Thread()里面的引數,大家學python每個模塊的功能時最好還是看一下源檔案內容,這樣有助于提高你的編程能力:

需要注意的點我已經打上標記了
import threading
def first():
print("frist active")
print("frist finish")
def main():
first_thread=threading.Thread(target=first,name="T1")
first_thread.start()#開始的標志
print("main")
if __name__ == '__main__':
main()
結果:
第一次運行
frist active
main
frist finish
第二次運行
frist active
frist finish
main
每次的結果不一樣就已經表明Frist和main是同時運行的了,
如果說效果不太明顯的話,我們改進一下接下來我們引入
import time
import threading
import time
def first():
print("frist active")
time.sleep(3)
print("frist finish")
def main():
first_thread=threading.Thread(target=first,name="T1")
first_thread.start()
print("main")
if __name__ == '__main__':
main()
結果:
frist active
main
frist finish
因為執行到Frist active的時候Frist執行緒要睡3秒這個時候main還在執行所以這樣每次都是這個結果了,
特別強調target=first不是匯入Frist函式從源檔案我們就已經看出是通過run()方法進行的,這里解釋我參考一位大佬解釋

鏈接
這位大佬大家應該都熟悉,就是頂頂大名的雷學委各位大佬可以去他的主頁看看可能會學到些新知識雷學委
當然如果你覺得這樣不行的話你也可以重寫threading.Thresd里的run方法來個自定義執行緒
class MyThread(threading.Thread):
def __init__(self,n):
super(MyThread,self).__init__() #重構run函式必須寫
self.n = n
def 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 t2
2s
2s
1s
1s
0s
0s
守護執行緒
所謂’執行緒守護’,就是主執行緒不管該執行緒的執行情況,只要是其他子執行緒結束且主執行緒執行完畢,主執行緒都會關閉,也就是說:主執行緒不等待該守護執行緒的執行完再去關閉,
不好理解的話來看看例子
import threading
import time
def first():
print("frist active")
time.sleep(3)
print("frist finish")
def second():
print("second active")
print("second finish")
def main():
first_thread=threading.Thread(target=first,name="T1")
second_thresd=threading.Thread(target=second,name="T2")
first_thread.setDaemon(True)#一定要在start()前開始
first_thread.start()
second_thresd.start()
print("main")
if __name__ == '__main__':
main()
結果
frist active
second active
second finishjiemeijieshu
main
當主執行緒和其他子執行緒都結束不管守護執行緒first_thread 結沒結束程式都結束
當設second_thresd為守護執行緒的時候情況是這樣的
import threading
import time
def first():
print("frist active")
time.sleep(3)
print("frist finish")
def second():
print("second active")
print("second finish")
def main():
first_thread=threading.Thread(target=first,name="T1")
second_thresd=threading.Thread(target=second,name="T2")
second_thresd.setDaemon(True)#一定要在start()前開始
first_thread.start()
second_thresd.start()
print("main")
if __name__ == '__main__':
main()
frist active
second active
second finish
main
frist finish #盡管輸出這個要等三秒
主行程等待子行程結束
為了讓守護執行緒執行結束之后,主執行緒再結束,我們可以使用join方法,讓主執行緒等待子執行緒執行
import threading
import time
def first():
print("frist active")
time.sleep(3)
print("frist finish")
def second():
print("second active")
print("second finish")
def main():
first_thread=threading.Thread(target=first,name="T1")
second_thresd=threading.Thread(target=second,name="T2")
first_thread.start()
second_thresd.start()
first_thread.join()
print("main")
if __name__ == '__main__':
main()
結果:
frist active
second active
second finish
frist finish
main
不加join是這樣的結果
frist active
second active
second finish
main
frist finish
共享全域變數的特性
這里定義一個全域變數A
import threading
import time
def first():
global A
print("frist active")
time.sleep(3)
A=A+3
print("frist:%d"%A)
print("frist finish")
def second():
global A
print("second active")
A=A+6
print("second:%d"%A)
print("second finish")
def main():
global A
first_thread=threading.Thread(target=first,name="T1")
second_thresd=threading.Thread(target=second,name="T2")
first_thread.start()
second_thresd.start()
#first_thread.join()
print("main")
A=A+3
print("mian:%d"%A)
if __name__ == '__main__':
A=0
main()
來看一下結果
frist active
second active
second:6
second finish
main
mian:9
frist:12
frist finish
鎖
由上面的例子可以看出,輸出A的值的時候不同行程之間的資源是共享的這就導致了變數A的值不固定造成了臟資料的情況,不理解的話我們就來個例子,

在沒有互斥鎖的情況下,假設賬戶有一萬元錢,存錢和取錢同時進行可能賬戶余額會有一萬一千元,這樣我當然高興只是銀行不答應,為了避免這種情況我們引入鎖的概念,下面我們簡單的介紹幾種編程里面常用的,
互斥鎖
import threading
import time
def first():
global A,lock
lock.acquire()
print("frist active")
time.sleep(3)
A=A+3
print("frist:%d"%A)
print("frist finish")
lock.release()
def second():
global A,lock
lock.acquire()
print("second active")
A=A+6
print("second:%d"%A)
print("second finish")
lock.release
def main():
global A,lock
lock=threading.Lock()
first_thread=threading.Thread(target=first,name="T1")
second_thresd=threading.Thread(target=second,name="T2")
first_thread.start()
second_thresd.start()
#first_thread.join()
print("main")
A=A+3
print("mian:%d"%A)
if __name__ == '__main__':
A=0
main()
結果
frist active
main
mian:3
frist:6
frist finish
second active
second:12
second finish
是不是這樣看著就舒服多了,如果例子不夠明顯我們再來一個
import threading
import time
def first():
global A,lock
lock.acquire()
print("frist active")
time.sleep(3)
A=A+3
print("frist1:%d"%A)
A = A + 3
print("frist2:%d" % A)
print("frist finish")
lock.release()
def second():
global A,lock
lock.acquire()
print("second active")
A=A+6
print("second1:%d"%A)
A=A+6
print("second2:%d"%A)
print("second finish")
lock.release()
def main():
global A,lock
lock=threading.Lock()
first_thread=threading.Thread(target=first,name="T1")
second_thresd=threading.Thread(target=second,name="T2")
first_thread.start()
second_thresd.start()
#first_thread.join()
print("main")
A=A+3
print("mian:%d"%A)
if __name__ == '__main__':
A=0
main()
結果
frist active
main
mian:3
frist1:6
frist2:9
frist finish
second active
second1:15
second2:21
second finish
去掉鎖以后結果
frist active
second active
second1:6
second2:12
second finish
main
mian:15
frist1:18
frist2:21
frist finish
很明顯去掉鎖以后結果雜亂的很
信號量
我相信對作業系統有一定了解的肯定,在剛才提到鎖的時候就想到了信號量畢竟考研題經常會出現,同步,互斥和信號量機制,我們就來說一說信號量鎖,其實道理很簡單假如你現在,在中國結婚了你只能娶一個老婆吧,盡管你可以去找別的女人但他們不能稱為老婆她們會被稱為小三,二奶啊等等,這里老婆這個信號量在中國就是一只能有一個,別的再來就不可以了,
import threading
import time
def run(n,semaphore):
semaphore.acquire() #加鎖
time.sleep(3)
print('run the thread:%s\n' % n)
semaphore.release() #釋放
if __name__== '__main__':
num=0
semaphore = threading.BoundedSemaphore(3) #最多允許3個執行緒同時運行
for i in range(10):
t = threading.Thread(target=run,args=('t-%s' % i,semaphore))
t.start()
while threading.active_count() !=1:
pass
else:
print('----------all threads done-----------')
結果
run the thread:t-2
run the thread:t-1
run the thread:t-0
run the thread:t-3
run the thread:t-5
run the thread:t-4
run the thread:t-6
run the thread:t-7
run the thread:t-8
run the thread:t-9
----------all threads done-----------
送點資源
肥學覺得python里面這些操作還是有點簡單的,如果各位大佬想繼續深究執行緒又沒有資源的話可以我這里有一本關于作業系統的書,領取可以私信我哦,好了今天的學習就到這里吧別忘了點贊三聯哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/289288.html
標籤:其他
