1. 程式人生 > 程式設計 >改變 Python 中執行緒執行順序的方法

改變 Python 中執行緒執行順序的方法

一、主執行緒會等待所有的子執行緒結束後才結束

首先我看下最普通情況下,主執行緒和子執行緒的情況。

import threading
from time import sleep,ctime

def sing():
 for i in range(3):
  print("正在唱歌...%d" % i)
  sleep(1)


def dance():
 for i in range(3):
  print("正在跳舞...%d" % i)
  sleep(1)


if __name__ == '__main__':
 print('---開始---:%s' % ctime())

 t1 = threading.Thread(target=sing)
 t2 = threading.Thread(target=dance)

 t1.start()
 t2.start()

 print('---結束---:%s' % ctime())

執行結果:

改變 Python 中執行緒執行順序的方法

最後一行列印的程式碼就算在一開始運行了,程式也不會結束。

只有等待所有的子執行緒(sing 和 dance)都執行完畢,主執行緒才會結束,即程式結束。

二、預設狀態下,多執行緒的執行順序是不確定的

我們先來看一段程式碼:

import threading
import time

class MyThread(threading.Thread):
 def run(self):
  for i in range(3):
   time.sleep(1)
   msg = "I'm "+self.name+' @ '+str(i)
   print(msg)

def test():
 for i in range(5):
  t = MyThread()
  t.start()

if __name__ == '__main__':
 test()

執行結果:

I'm Thread-1 @ 0
I'm Thread-2 @ 0
I'm Thread-3 @ 0
I'm Thread-4 @ 0
I'm Thread-5 @ 0
I'm Thread-1 @ 1
I'm Thread-3 @ 1
I'm Thread-2 @ 1
I'm Thread-4 @ 1
I'm Thread-5 @ 1
I'm Thread-1 @ 2
I'm Thread-3 @ 2
I'm Thread-2 @ 2
I'm Thread-4 @ 2
I'm Thread-5 @ 2

每次的執行結果可能都不一樣,但大體差不多。

說明:

從程式碼和執行結果我們可以看出,多執行緒程式的執行順序是不確定的。

當執行到 sleep 語句時,執行緒將被阻塞,到 sleep 結束後,執行緒進入就緒狀態,等待排程,而執行緒排程將自行選擇一個執行緒執行。

上面的程式碼中只能保證每個執行緒都執行完整個 run 函式,但是執行緒的啟動順序、run 函式中每次迴圈的執行順序都不能確定。

總結

每個執行緒預設有一個名字,儘管上面的例子中沒有指定執行緒物件的 name,但是 python 會自動為執行緒指定一個名字。

當執行緒的 run() 方法結束時該執行緒完成。

無法控制執行緒排程程式,但可以通過別的方式來影響執行緒排程的方式。

三、Python daemon 守護執行緒詳解

當程式中擁有多個執行緒時,主執行緒執行結束並不會影響子執行緒繼續執行。

換句話說,只有程式中所有執行緒全部執行完畢後,程式才算真正結束。

Python 還支援建立另一種執行緒,稱為守護執行緒(或後臺執行緒)。

此類執行緒的特點是,當程式中主執行緒及所有非守護執行緒執行結束時,未執行完畢的守護執行緒也會隨之消亡,程式將結束執行。

守護執行緒本質也是執行緒,因此其建立方式和普通執行緒一樣,唯一不同之處在於,將普通執行緒設為守護執行緒,需通過執行緒物件呼叫其 damon 屬性,將該屬性的值改為 True。

注意:執行緒物件呼叫 daemon 屬性必須在呼叫 start() 方法之前,否則 Python 直譯器將報 RuntimeError 錯誤。

import threading

def action(len):
 for i in range(len):
  print(threading.current_thread().getName() + "," + str(i))

def main():
 t1 = threading.Thread(target=action,args=(10,))
 # 設定子執行緒為守護程序
 t1.daemon = True
 t1.start()

 for i in range(3):
  print(threading.current_thread().getName()+','+str(i))

if __name__ == "__main__":
 main()

執行結果:

Thread-1,0
MainThread,1
MainThread,2

程式中,子執行緒裡的程式就迴圈了一次,接著主執行緒執行完後,子執行緒就不列印資訊了。

由於該程式中除了守護執行緒就只有主執行緒,因此只要主執行緒執行結束,則守護執行緒也隨之消亡。

四、控制執行緒執行順序

通過前面的學習我們知道,主執行緒和子執行緒會輪流獲得 CPU 的資源。

但有時候,我們想讓某個子執行緒先執行,然後再讓主執行緒執行程式碼,該如何實現呢?

很簡單,通過呼叫執行緒物件的 join() 方法即可。

join() 方法的功能是在程式指定位置,優先讓該方法的呼叫者使用 CPU 資源。

該方法的語法格式如下:

thread.join( [timeout] )

timeout 引數作為可選引數,其功能是指定 thread 執行緒最多可以霸佔 CPU 資源的時間(以秒為單位)。

如果省略,則預設直到 thread 執行結束(進入死亡狀態)才釋放 CPU 資源。

我們仍舊拿上面的例子來舉例:

import threading

def action(len):
 for i in range(len):
  print(threading.current_thread().getName() + ",))
 # 設定子執行緒為守護程序
 t1.daemon = True
 t1.start()
 t1.join()
 for i in range(3):
  print(threading.current_thread().getName()+','+str(i))

if __name__ == "__main__":
 main()

我們在子執行緒呼叫的後面,添加了 t1.join()。

執行結果:

Thread-1,0
Thread-1,1
Thread-1,2
Thread-1,3
Thread-1,4
Thread-1,5
Thread-1,6
Thread-1,7
Thread-1,8
Thread-1,9
MainThread,2

上面的例子中,t1 執行緒呼叫了 join() 方法,並且沒有指定具體的 timeout 引數值。

這意味著如果程式想繼續往下執行,必須先執行完 t1 子執行緒。

以上就是改變 Python 中執行緒的執行順序的方法的詳細內容,更多關於改變 Python 中執行緒的執行順序的資料請關注我們其它相關文章!