前言:本系列將包含Python並行程式設計的相關技術內容,包括Python執行緒、Python程式、併發程式設計的非同步模式及終極大法Python分散式計算如Celery、SCOOP等相關技術。
關鍵詞: threading multiprocessing asyncio Celery
執行緒的基本概念和執行緒的兩種定義方法
執行緒是什麼?
執行緒看起來就像輕量級的程式,而程式又是什麼呢? 程式即我們平時執行程式,比如通過點選圖示開啟的瀏覽器,QQ都是程式,程式擁有自己的獨立的記憶體空間地址,可以擁有多個執行緒;即執行緒是存在程式內,也就意味著一個程式內的執行緒可以共享一些資源,其執行緒間的切換也就比程式低得多,多個執行緒可以並行及併發執行,共享資料和資源,所以我們多數時候的執行緒通訊都是利用共享資訊的空間進行通訊,這也是後面談到的執行緒管理必備的多種執行緒通訊方式了。
在Python怎麼定義執行緒?
使用執行緒最簡單的方式就是通過目標函式的例項化:
import threading
import time
# 用於例項化執行緒目標函式
def function(i):
time.sleep(2)
print('Thread {} is running.'.format(i))
time.sleep(2)
return
for i in range(5):
# Python模組threading.Thread方法
t = threading.Thread(target=function, args=(i, ))
t.start()
複製程式碼
執行截圖如下:
通過以上程式我們看出,定義好我們需要執行的目標函式來例項化執行緒,然後傳入引數target
即函式名,然後如果需要執行的目標函式有引數需要傳遞的話即可傳入args
元組,注意此處傳入的是元組tuple
。
然後我們在呼叫start()
方法後啟動例項化的執行緒
使用執行緒模組實現新的執行緒:
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
for i in range(1, 6):
t = myThread(i)
t.start()
複製程式碼
執行截圖如下:
通過上面的程式我們可以看出,我們需要定義新的Thread類的子類,並且通過重寫__init__
方法來傳遞引數,然後重寫run()
方法來實現目標函式,那麼當我們建立出新的子類後就可以例項化該子類並通過start()
方法來啟動執行緒。
守護執行緒 setDaemon(True)
接下來我們在執行一段程式碼:
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
print('Mian THread starting')
for i in range(1, 6):
t = myThread(i)
t.start()
print('Mian THread end')
複製程式碼
執行截圖如下:
當一個程式啟動之後,會預設產生一個主執行緒,因為執行緒是程式執行流的最小單元,當設定多執行緒時,主執行緒會建立多個子執行緒;我們在主執行緒新增了兩句print()
用於列印主執行緒的執行狀態,我們可以看見在預設情況下主現成直接執行完就退出了,此時子執行緒們還在執行過程中,那麼如果我們新增setDaemon(True)方法呢:
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
print('Mian THread starting')
for i in range(1, 6):
t = myThread(i)
t.setDaemon(True)
t.start()
print('Mian THread end')
複製程式碼
執行截圖如下:
我們可以在執行截圖中看到,當我們使用setDaemon(True)方法,設定子執行緒為守護執行緒時,主執行緒一旦執行結束,則全部執行緒全部被終止執行,可能出現的情況就是,子執行緒的任務還沒有完全執行結束,就被迫停止。 那麼我們能不能讓主執行緒等等我們的子執行緒,等待子執行緒執行結束後,主執行緒再終止呢,即實現守護執行緒相反的效果,答案是可以得。阻塞執行緒 join()
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
print('Mian THread starting')
threads = []
for i in range(1, 6):
t = myThread(i)
t.start()
threads.append(t)
for t in threads:
t.join()
print('Mian THread end')
複製程式碼
執行截圖如下:
我們可以看見主執行緒是在等待子執行緒執行結束才終止執行的,即join()
所完成的工作就是執行緒同步,即主執行緒任務結束之後,進入阻塞狀態,一直等待其他的子執行緒執行結束之後,主執行緒再終止。