Python並行程式設計(一):執行緒的基本概念和執行緒的兩種定義方法以及join()、setDaemon(True)的使用

若數發表於2019-04-08

前言:本系列將包含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()所完成的工作就是執行緒同步,即主執行緒任務結束之後,進入阻塞狀態,一直等待其他的子執行緒執行結束之後,主執行緒再終止。

相關文章