對於多線程的理解,通俗的講就是程序在同一時間執行多個任務。與多線程相對的就是單線程,同一時間只做一件事,要麼是聽音樂,要麼是看電影;而多線程則是可以一邊聽音樂,又可以一邊看電影。
單線程
首先舉一個單線程的例子:
# example 1
from time import ctime, sleep
def music():
for i in range(2):
print('Start Listening Music: %s' % ctime())
sleep(1)
print('Finish Listening Music: %s' % ctime())
def movie():
for i in range(2):
print('Start Watching Movie: %s' % ctime())
sleep(5)
print('Finish Watching Movie: %s' % ctime())
if __name__ == '__main__':
music()
movie()
print('All spent: %s' % ctime())
# result 1
Start Listening Music: Mon Aug 26 19:22:21 2019
Finish Listening Music: Mon Aug 26 19:22:22 2019
Start Listening Music: Mon Aug 26 19:22:22 2019
Finish Listening Music: Mon Aug 26 19:22:23 2019
Start Watching Movie: Mon Aug 26 19:22:23 2019
Finish Watching Movie: Mon Aug 26 19:22:28 2019
Start Watching Movie: Mon Aug 26 19:22:28 2019
Finish Watching Movie: Mon Aug 26 19:22:33 2019
All spent: Mon Aug 26 19:22:33 2019
上面這個例子是聽音樂和看電影分開處理的,先聽音樂,聽了兩首,每首1秒鐘;然後是看電影,看了兩部,每部5秒鐘。程序的總共執行了12秒。
多線程
多線程就是將聽音樂和看電影同時進行。在Python中多線程使用thread和threading模塊。thread模塊提供了基本的線程和鎖定支持,而threading模塊提供了更高級別,功能更全面的線程管理。
"更高級別的threading模塊更爲先進,對線程支持更爲完善,
而且使用thread模塊裏的屬性有可能會與threading出現衝突。
其次,低級別的thread模塊的同步原語很少(實際上只有一個),而threading模塊則有很多。"——《Python核心編程》
所以在這裏推薦使用threading模塊來進行python多線程。
在threading模塊中主要提供了一下方法:
方法與屬性 | 描述 |
---|---|
current_thread() | 返回當前線程 |
active_count() | 返回當前活躍的線程數,1個主線程+n個子線程 |
get_ident() | 返回當前線程 |
enumerater() | 返回當前活動 Thread 對象列表 |
main_thread() | 返回主 Thread 對象 |
settrace(func) | 爲所有線程設置一個 trace 函數 |
setprofile(func) | 爲所有線程設置一個 profile 函數 |
stack_size([size]) | 返回新創建線程棧大小;或爲後續創建的線程設定棧大小爲 size |
TIMEOUT_MAX | Lock.acquire(), RLock.acquire(), Condition.wait() 允許的最大超時時間 |
threading.Thread類
對於執行多線程,使用的是Thread類,它的定義如下:
threading.Thread(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)
- 參數group是預留的,用於將來擴展;
- 參數target是一個可調用對象,在線程啓動後執行;
- 參數name是線程的名字。默認值爲“Thread-N“,N是一個數字;
- 參數args和kwargs分別表示調用target時的參數列表和關鍵字參數;
- daemon表示是否是守護線程,默認爲False,守護線程是指當主線程結束後該子線程也會隨之結束,是主線程的守護。
下面是執行多線程的一個例子:
# example 2
import threading
from time import ctime, sleep
def music():
for i in range(2):
print('%s Start Listening Music: %s' % (threading.current_thread().getName(), ctime()))
sleep(1)
print('%s Finish Listening Music: %s' % (threading.current_thread().getName(), ctime()))
def movie():
for i in range(2):
print('%s Start Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
sleep(5)
print('%s Finish Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
if __name__ == '__main__':
threads = []
t1 = threading.Thread(target=music, daemon=True)
t2 = threading.Thread(target=movie, daemon=True)
threads.append(t1)
threads.append(t2)
for t in threads:
t.start()
print('All spent: %s' % ctime())
# result 2
Thread-1 Start Listening Music: Mon Aug 26 19:40:49 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:40:49 2019
All spent: Mon Aug 26 19:40:49 2019
從上面的結果可以看到,這並不是我們想要的結果,因爲Thread-1和Thread-2纔剛執行還沒執行完畢程序就已經終止。這是因爲兩個子線程的daemon屬性都設置成True,成爲主線程的守護線程。那麼我們將daemon屬性設置成False能否得到想要的結果呢?
daemon屬性
# example 3
import threading
from time import ctime, sleep
def music():
for i in range(2):
print('%s Start Listening Music: %s' % (threading.current_thread().getName(), ctime()))
sleep(1)
print('%s Finish Listening Music: %s' % (threading.current_thread().getName(), ctime()))
def movie():
for i in range(2):
print('%s Start Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
sleep(5)
print('%s Finish Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
if __name__ == '__main__':
threads = []
t1 = threading.Thread(target=music)
t2 = threading.Thread(target=movie)
threads.append(t1)
threads.append(t2)
for t in threads:
t.start()
print('All spent: %s' % ctime())
# result 3
Thread-1 Start Listening Music: Mon Aug 26 19:47:05 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:47:05 2019
All spent: Mon Aug 26 19:47:05 2019
Thread-1 Finish Listening Music: Mon Aug 26 19:47:06 2019
Thread-1 Start Listening Music: Mon Aug 26 19:47:06 2019
Thread-1 Finish Listening Music: Mon Aug 26 19:47:07 2019
Thread-2 Finish Watching Movie: Mon Aug 26 19:47:10 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:47:10 2019
Thread-2 Finish Watching Movie: Mon Aug 26 19:47:15 2019
從結果中可以看到這並不是我們想要的結果。雖然子線程Thread-1和Thread-2同時開始,但是子線程還沒結束主線程(All spent)已經結束,我們想要的是主線程在所有子線程結束後才結束。這就需要用到join()方法。
join()方法
join()方法的作用是在子線程完成運行之前,這個子線程的父線程將一直被阻塞。簡而言之就是希望主線程等等子線程,直到子線程執行完畢。
# example 4
import threading
from time import ctime, sleep
def music():
for i in range(2):
print('%s Start Listening Music: %s' % (threading.current_thread().getName(), ctime()))
sleep(1)
print('%s Finish Listening Music: %s' % (threading.current_thread().getName(), ctime()))
def movie():
for i in range(2):
print('%s Start Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
sleep(5)
print('%s Finish Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
if __name__ == '__main__':
threads = []
t1 = threading.Thread(target=music, daemon=True)
t2 = threading.Thread(target=movie, daemon=True)
threads.append(t1)
threads.append(t2)
for t in threads:
t.start()
t.join()
print('All spent: %s' % ctime())
# result 4
Thread-1 Start Listening Music: Mon Aug 26 19:52:25 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:52:25 2019
Thread-1 Finish Listening Music: Mon Aug 26 19:52:26 2019
Thread-1 Start Listening Music: Mon Aug 26 19:52:26 2019
Thread-1 Finish Listening Music: Mon Aug 26 19:52:27 2019
Thread-2 Finish Watching Movie: Mon Aug 26 19:52:30 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:52:30 2019
Thread-2 Finish Watching Movie: Mon Aug 26 19:52:35 2019
All spent: Mon Aug 26 19:52:35 2019
可以看到整個過程用了10s,比單線程快了2s,這是因爲看電影用了10s,在看電影的過程中聽音樂已經結束,等電影結束後主進程才結束。如果將看電影調整爲4s呢?
# example 5
import threading
from time import ctime, sleep
def music():
for i in range(2):
print('%s Start Listening Music: %s' % (threading.current_thread().getName(), ctime()))
sleep(4)
print('%s Finish Listening Music: %s' % (threading.current_thread().getName(), ctime()))
def movie():
for i in range(2):
print('%s Start Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
sleep(5)
print('%s Finish Watching Movie: %s' % (threading.current_thread().getName(), ctime()))
if __name__ == '__main__':
threads = []
t1 = threading.Thread(target=music, daemon=True)
t2 = threading.Thread(target=movie, daemon=True)
threads.append(t1)
threads.append(t2)
for t in threads:
t.start()
print('Start Main Thread: %s' % ctime())
sleep(2)
t.join()
print('Finish Main Thread: %s' % ctime())
print('All spent: %s' % ctime())
# result 5
Thread-1 Start Listening Music: Mon Aug 26 19:55:35 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:55:35 2019
Start Main Thread: Mon Aug 26 19:55:35 2019
Thread-1 Finish Listening Music: Mon Aug 26 19:55:39 2019
Thread-1 Start Listening Music: Mon Aug 26 19:55:39 2019
Thread-2 Finish Watching Movie: Mon Aug 26 19:55:40 2019
Thread-2 Start Watching Movie: Mon Aug 26 19:55:40 2019
Thread-1 Finish Listening Music: Mon Aug 26 19:55:43 2019
Thread-2 Finish Watching Movie: Mon Aug 26 19:55:45 2019
Finish Main Thread: Mon Aug 26 19:55:45 2019
All spent: Mon Aug 26 19:55:45 2019
可以看到雖然聽音樂增加到了4s,但是總過程還是10s,這是取決於兩個子線程時間最長的那一個,即看電影。
從上面的例子中可以總結出,daemon是將該子線程設置爲守護線程,join()方法的作用是阻塞主線程直到子線程結束。
自定義線程
自定義線程的步驟:
(1)繼承Thread類
(2)重寫__init__方法添加自己的屬性,使用super加載父類屬性
(3)重寫run方法
import threading
class MyThreading(threading.Thread):
def __init__(self, func, arg):
super(MyThreading,self).__init__()
self.func = func
self.arg = arg
def run(self):
self.func(self.arg)
def my_func(args):
"""
to do
"""
pass
obj = MyThreading(my_func, 123)
obj.start()
線程鎖
多個進程同時進行的時候呢,若同時對一個變量訪問,那就會出現混亂,具體的混亂可以看下面的例子:
# example 6
import threading
import time
number = 0
def plus():
global number # global聲明此處的number是外面的全局變量number
print("Start %s, time = %s" % (threading.current_thread().getName(), time.ctime()))
for _ in range(1000000):
number += 1
print("Finish %s, number = %s, time = %s" % (threading.current_thread().getName(), number, time.ctime()))
print('Start: %s' % time.ctime())
for i in range(2):
t = threading.Thread(target=plus)
t.start()
time.sleep(2) # 等待2秒,確保2個子線程都已經結束運算。
print("Finish Main Thread, number = ", number)
# result 6
Start: Mon Aug 26 20:08:39 2019
Start Thread-1, time = Mon Aug 26 20:08:39 2019
Start Thread-2, time = Mon Aug 26 20:08:39 2019
Finish Thread-2, number = 1132339, time = Mon Aug 26 20:08:39 2019
Finish Thread-1, number = 1144554, time = Mon Aug 26 20:08:39 2019
Finish Main Thread, number = 1144554
程序主要是從0每次加1加到999999,理想結果應該是每個線程爲1000000,最後的輸出結果是2000000。而運行的結果卻是1144554,說明多線程對單變量的訪問出現了混亂,並且這種混亂是每次執行的結果都不一樣。那麼如何保證在某一時刻只有一個線程可以修改變量呢?這就需要引入線程鎖。
threading模塊的線程鎖主要有一下幾種:
- Lock 互斥鎖
- RLock 可重入鎖
- Semaphore 信號
- Event 事件
- Condition 條件
- Barrier “阻礙”
Lock互斥鎖
互斥鎖是指同一時刻只有一個線程可以訪問共享的數據。首先初始化鎖對象,然後將鎖當做參數傳遞給任務函數,在任務中加鎖,使用後釋放鎖。
# example 7
import threading
import time
def plus(lk):
global number # global聲明此處的number是外面的全局變量number
lk.acquire() # 開始加鎖
print("Start %s, time = %s" % (threading.current_thread().getName(), time.ctime()))
for _ in range(10000000):
number += 1
print("Finish %s, number = %s, time = %s" % (threading.current_thread().getName(), number, time.ctime()))
lk.release() # 釋放鎖,讓別的線程也可以訪問number
if __name__ == '__main__':
number = 0
lock = threading.Lock()
print('Start: %s' % time.ctime())
for i in range(2):
t = threading.Thread(target=plus, args=(lock,))
t.start()
t.join()
print("Finish Main Thread, number = ", number)
# result 7
Start: Mon Aug 26 20:24:22 2019
Start Thread-1, time = Mon Aug 26 20:24:22 2019
Finish Thread-1, number = 10000000, time = Mon Aug 26 20:24:24 2019
Start Thread-2, time = Mon Aug 26 20:24:24 2019
Finish Thread-2, number = 20000000, time = Mon Aug 26 20:24:26 2019
Finish Main Thread, number = 20000000
Semaphore信號
信號的用法跟互斥鎖非常的相似,原理與線程鎖並沒有多大的區別,只不過線程鎖鎖住一個線程在運行和修改數據,而信號量可以自己控制同一時刻運行幾個線程和幾個線程修改數據,也就是設置最大同時運行的線程數.
# example 8
import time
import threading
def run(n, se):
se.acquire()
print("%s run the thread: %s" % (threading.current_thread().getName(), n))
time.sleep(1)
se.release()
# 設置允許5個線程同時運行
semaphore = threading.BoundedSemaphore(5)
for i in range(20):
t = threading.Thread(target=run, args=(i, semaphore))
t.start()
# result 8
Thread-1 run the thread: 0
Thread-2 run the thread: 1
Thread-3 run the thread: 2
Thread-4 run the thread: 3
Thread-5 run the thread: 4
Thread-6 run the thread: 5
Thread-8 run the thread: 7
Thread-7 run the thread: 6
Thread-9 run the thread: 8
Thread-10 run the thread: 9
Thread-11 run the thread: 10
Thread-12 run the thread: 11
Thread-13 run the thread: 12
Thread-14 run the thread: 13
Thread-15 run the thread: 14
Thread-16 run the thread: 15
Thread-18 run the thread: 17
Thread-17 run the thread: 16
Thread-19 run the thread: 18
Thread-20 run the thread: 19
Event信號
使用方法:e = threading.Event()
Event對象主要用於線程間通信,確切地說是用於主線程控制其他線程的執行。
Event事件提供了四個方法:wait()、clear()、set()和is_set()。
Event事件實現通信機制:全局定義了一個“Flag”(默認爲False),若調用clear()則Flag爲False,執行event.wait方法時會阻塞;調用set()則Flag爲True,則執行event.wait方法時便不阻塞,判斷Flag狀態用is_set()。默認Flag爲False時會阻塞。
下面使用Event時間模擬信號燈的一個程序,紅燈綠燈時間均爲5s,若紅燈亮,則車輛出於等待狀態,若綠燈亮,則車輛行駛。
# example 9
# 利用Event類模擬紅綠燈
import threading
import time
event = threading.Event()
def lighter():
green_time = 5 # 綠燈時間
red_time = 5 # 紅燈時間
event.set() # 初始設爲綠燈
while True:
print("\33[32;0m 綠燈亮...\033[0m")
time.sleep(green_time)
event.clear()
print("\33[31;0m 紅燈亮...\033[0m")
time.sleep(red_time)
event.set()
def run(name):
while True:
if event.is_set(): # 判斷當前是否"放行"狀態
print("一輛[%s] 呼嘯開過..." % name)
time.sleep(1)
else:
print("一輛[%s]開來,看到紅燈,無奈的停下了..." % name)
event.wait()
print("[%s] 看到綠燈亮了,瞬間飛起....." % name) # 等待信號燈爲True後執行
if __name__ == '__main__':
timer = threading.Timer(15, lighter)
timer.start()
light = threading.Thread(target=lighter, )
light.start()
for name in ['奔馳', '寶馬', '奧迪']:
car = threading.Thread(target=run, args=(name,))
car.start()
timer.cancel()
# result 9
綠燈亮...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
紅燈亮...
一輛[奔馳]開來,看到紅燈,無奈的停下了...
一輛[寶馬]開來,看到紅燈,無奈的停下了...
一輛[奧迪]開來,看到紅燈,無奈的停下了...
綠燈亮...
[奔馳] 看到綠燈亮了,瞬間飛起.....
一輛[奔馳] 呼嘯開過...
[奧迪] 看到綠燈亮了,瞬間飛起.....
一輛[奧迪] 呼嘯開過...
[寶馬] 看到綠燈亮了,瞬間飛起.....
一輛[寶馬] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
紅燈亮...
一輛[寶馬]開來,看到紅燈,無奈的停下了...
一輛[奔馳]開來,看到紅燈,無奈的停下了...
一輛[奧迪]開來,看到紅燈,無奈的停下了...
綠燈亮...
[寶馬] 看到綠燈亮了,瞬間飛起.....
[奔馳] 看到綠燈亮了,瞬間飛起.....
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
[奧迪] 看到綠燈亮了,瞬間飛起.....
一輛[奧迪] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[奔馳] 呼嘯開過...
一輛[奧迪] 呼嘯開過...
一輛[寶馬] 呼嘯開過...
紅燈亮...
一輛[寶馬]開來,看到紅燈,無奈的停下了...
一輛[奔馳]開來,看到紅燈,無奈的停下了...
一輛[奧迪]開來,看到紅燈,無奈的停下了...
Condition條件變量
條件變量是指當某一線程滿足要求後,其他線程才能執行。
比如喫火鍋的時候,有放魚丸的人和喫魚丸的人,當放魚丸達到一定數量的時候(比如5個),然後通知大家來喫魚丸。如果魚丸喫完了,那麼就會通知放魚丸的人來放魚丸。當放了5個的時候又通知其他人喫魚丸...這是一個生產者和消費者行爲。
Condition(條件變量)通常與一個鎖關聯。需要在多個Contidion中共享一個鎖時,可以傳遞一個Lock/RLock實例給構造方法,否則它將自己生成一個RLock實例。
可以認爲,除了Lock帶有的鎖定池外,Condition還包含一個等待池,池中的線程處於狀態圖中的等待阻塞狀態,直到另一個線程調用notify()/notifyAll()通知;得到通知後線程進入鎖定池等待鎖定。
Condition():
- acquire(): 線程鎖
- release(): 釋放鎖
- wait(timeout): 線程掛起,直到收到一個notify通知或者超時(可選的,浮點數,單位是秒s)纔會被喚醒繼續運行。wait()必須在已獲得Lock前提下才能調用,否則會觸發RuntimeError。
- notify(n=1): 通知其他線程,那些掛起的線程接到這個通知之後會開始運行,默認是通知一個正等待該condition的線程,最多則喚醒n個等待的線程。notify()必須在已獲得Lock前提下才能調用,否則會觸發RuntimeError。notify()不會主動釋放Lock。
- notifyAll(): 如果wait狀態線程比較多,notifyAll的作用就是通知所有線程。
# example 10
import threading
import time
con = threading.Condition()
num = 0
# 生產者
class Producer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
# 鎖定線程
global num
con.acquire()
while True:
if num == 0:
print("開始添加!!!")
num += 1
print("火鍋裏面魚丸個數:%s" % str(num))
time.sleep(1)
if num >= 5:
print("火鍋裏面裏面魚丸數量已經到達5個,無法添加了!")
# 喚醒等待的線程
con.notify() # 喚醒小夥伴開喫啦
# 等待通知
con.wait()
# 釋放鎖
con.release()
# 消費者
class Consumers(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
con.acquire()
global num
while True:
if num == 5:
print("開始喫啦!!!")
num -= 1
print("火鍋裏面剩餘魚丸數量:%s" % str(num))
time.sleep(2)
if num <= 0:
print("鍋底沒貨了,趕緊加魚丸吧!")
con.notify() # 喚醒其它線程
# 等待通知
con.wait()
con.release()
p = Producer()
c = Consumers()
p.start()
c.start()
# result 10
開始添加!!!
火鍋裏面魚丸個數:1
火鍋裏面魚丸個數:2
火鍋裏面魚丸個數:3
火鍋裏面魚丸個數:4
火鍋裏面魚丸個數:5
火鍋裏面裏面魚丸數量已經到達5個,無法添加了!
開始喫啦!!!
火鍋裏面剩餘魚丸數量:4
火鍋裏面剩餘魚丸數量:3
火鍋裏面剩餘魚丸數量:2
火鍋裏面剩餘魚丸數量:1
火鍋裏面剩餘魚丸數量:0
鍋底沒貨了,趕緊加魚丸吧!
開始添加!!!
火鍋裏面魚丸個數:1
火鍋裏面魚丸個數:2
火鍋裏面魚丸個數:3
火鍋裏面魚丸個數:4
火鍋裏面魚丸個數:5
火鍋裏面裏面魚丸數量已經到達5個,無法添加了!
開始喫啦!!!
火鍋裏面剩餘魚丸數量:4
火鍋裏面剩餘魚丸數量:3
火鍋裏面剩餘魚丸數量:2
火鍋裏面剩餘魚丸數量:1
火鍋裏面剩餘魚丸數量:0
鍋底沒貨了,趕緊加魚丸吧!
類似的其他例子:https://blog.csdn.net/comprel/article/details/72798407
Timer定時器
指定n秒s執行某個操作
from threading import Timer
def hello():
print("hello, world")
# 表示1秒後執行hello函數
t = Timer(1, hello)
t.start()
Queue實現結果存儲
由於多線程中沒有返回值,若有些函數需要return返回值該怎麼辦呢?那就需要導入queue模塊來存儲各線程的返回值。
# example 11
import threading
from queue import Queue
def job(l, q):
for i in range(len(l)):
l[i] = l[i] ** 2
q.put(l)
# return l # 本來這裏應該是將列表l返回的,現在存儲在隊列中
if __name__ == '__main__':
q = Queue()
threads = []
data = [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]
for i in range(len(data)):
t = threading.Thread(target=job, args=(data[i], q))
t.start()
threads.append(t)
for thread in threads:
thread.join()
result = []
for _ in range(len(data)):
result.append(q.get())
print(result)
# result 11
[[1, 4, 9], [4, 9, 16], [9, 16, 25], [16, 25, 36]]
with語句
鎖的鎖定與釋放與文件的打開與關閉類似,若打開了鎖未能正確關閉則會影響程序的進行,因此同樣可以用with語句來自動關閉鎖:
with some_lock:
# 執行任務...
等同於:
some_lock.acquire()
try:
# 執行任務..
finally:
some_lock.release()
全局解釋器鎖GIL(Global Interpreter Lock)
python在設計之初就考慮到在解釋器的主循環中,同時只有一個線程在運行。即在任意時刻只有一個線程在解釋器中運行。對python虛擬機訪問的控制由全局解釋鎖GIL控制,正是這個鎖來控制同一時刻只有一個線程能夠運行。
詳細參考: