Python多線程的理解和使用(一)Threading中join()函數的理解


1. 多線程的概念

多線程類似於同時執行多個不同程序,多線程運行有如下優點:

使用線程可以把占據長時間的程序中的任務放到后台去處理。
用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度 
程序的運行速度可能加快
在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如內存占用等等。
線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。

每個線程都有他自己的一組CPU寄存器,稱為線程的上下文,該上下文反映了線程上次運行該線程的CPU寄存器的狀態。

指令指針和堆棧指針寄存器是線程上下文中兩個最重要的寄存器,線程總是在進程得到上下文中運行的,這些地址都用於標志擁有線程的進程地址空間中的內存。

線程可以被搶占(中斷)。
在其他線程正在運行時,線程可以暫時擱置(也稱為睡眠) -- 這就是線程的退讓。
 

2. Threading 多進程的使用案例:join()函數的理解

     通過以下實例可以get到join()函數的作用:如果thread是某個子線程,則調用thread.join()的作用是確保thread子線程執行完畢后才能執行下一個線程。下面第一個例子中沒有調用join()函數,故沒有這個限制,所有線程執行順序都不定。

     第二個例子中在每個子線程啟動start()后馬上調用了join()函數,這就確保了對於每一個子線程,必須等它執行完畢后才能執行下一個程序,故子線程是按順序執行的,且主線程中的print()方法是在所有的子線程執行完畢后才執行。

    第三個例子中,對於子線程啟動start()后沒有馬上調用join()函數,故子線程的執行順序是不確定的,但是主線程中的print()前調用了每個子線程的join()函數,故print()要在所有的子線程執行完畢后才能執行。

(1)沒有使用join()函數,線程執行順序不定,主線程可能在所有子線程執行完之前就執行了

import threading
import time

def test(p):
time.sleep(0.001)
print(p)

ts = []

for i in range(15):
# target指定線程要執行的代碼,args指定該代碼的參數
th = threading.Thread(target=test, args=[i])
ts.append(th)

for i in ts:
i.start()

print("it is end !")



0
1
it is end !
4
2
3
5
(2)修改部分代碼如下:每次啟動子線程后,調用一次join()函數,可以看出線程按順序執行,且主線程在所有子線程執行完之              后才執行。

for i in ts:
i.start()
# 此處的join函數子線程按順序執行,即i線程跑完后才能繼續跑下一個線程
i.join()


print("it is end !")



0
1
2
3
4
5
it is end !
(3)修改部分代碼如下:可以看出子線程執行順序不定,但是主線程是在所有子線程執行完畢之后才執行的。

for i in ts:
i.start()

# 此處的join函數使子線程全部跑完再繼續往下跑子線程
for i in ts:
i.join()

print("it is end !")


1
0
4
5
2
3
it is end !
 

3. 全局鎖

(1)全局鎖(GIL)是一個很重要的概念。

在任意一個指定的時間,有且只有一個線程在運行 -》 python是線程安全的

(2)io操作經常用到多線程,如在修改某個文檔時,其他線程是不能進來干擾的。

    a. 加鎖:acquire , 釋放鎖:release,   有加鎖就一定要釋放鎖

(3).rlock 可重入鎖: 如果前面忘記了release釋放鎖,正常是無法再獲取鎖的,rlock可實現再獲取鎖。

(4)實例:mlock.acquire()和mlock.release()之間的代碼是不間斷執行的,不會被其他線程干擾。

import threading

mlock = threading.Lock()
lst = list(range(20))

def change():
global lst
# mlock.acquire() # 加鎖
lst = [i+1 for i in lst]
lst = [i*2 for i in lst]
# mlock.release() #釋放鎖

print(lst)

for i in range(6):
d = threading.Thread(target=change)
d.start()


[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40]
[6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66, 70, 74, 78, 82]
[14, 22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 142, 150, 158, 166]
[30, 46, 62, 78, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 254, 270, 286, 302, 318, 334]
[62, 94, 126, 158, 190, 222, 254, 286, 318, 350, 382, 414, 446, 478, 510, 542, 574, 606, 638, 670]
[126, 190, 254, 318, 382, 446, 510, 574, 638, 702, 766, 830, 894, 958, 1022, 1086, 1150, 1214, 1278,  1342]
---------------------
作者:zhuzuwei
來源:CSDN
原文:https://blog.csdn.net/zhuzuwei/article/details/80927554
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM