【python】多線程(基礎(chǔ)篇): join() 函數(shù)、is_alive()方法

線程

什么是線程

(1)線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。
(2)它被包含在進(jìn)程之中,是進(jìn)程中的實際運(yùn)作單位。
(3)一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)。
(4)一個線程是一個execution context(執(zhí)行上下文),即一個cpu執(zhí)行時所需要的一串指令。

【重點】一個程序運(yùn)行后至少有一個進(jìn)程,一個進(jìn)程中可以包含多個線程;


線程的工作方式

CPU會給你一個在同一時間能夠做多個運(yùn)算的幻覺,實際上它在每個運(yùn)算上只花了極少的時間,本質(zhì)上CPU同一時刻只干了一件事。它能這樣做就是因為它有每個運(yùn)算的execution context。就像你能夠和你朋友共享同一本書一樣,多任務(wù)也能共享同一塊CPU。


啟動多個線程(函數(shù)實現(xiàn))

Python提供了一個內(nèi)置模塊 threading.Thread,可以很方便地讓我們創(chuàng)建多線程。 threading.Thread() 一般接收兩個參數(shù):

  • 線程函數(shù)名:要放置線程讓其后臺執(zhí)行的函數(shù),由我們自已定義,注意不要加();

  • 線程函數(shù)的參數(shù):線程函數(shù)名所需的參數(shù),以元組的形式傳入。若不需要參數(shù),可以不指定。

【舉個例子】:

import threading
import time
def run(n):
    print("task ",n )
    time.sleep(2)

# run("t1")
# run("t2")
t1 = threading.Thread(target=run,args=("t1",))#生成一個線程實例
t2 = threading.Thread(target=run,args=("t2",))
t1.start()
t2.start()

【輸出】:
task  t1
task  t2

【解釋】由于每個方法都有單獨的進(jìn)程,會同時開始執(zhí)行,上面代碼會同時輸出


啟動多個線程(類實現(xiàn))

相比較函數(shù)而言,使用類創(chuàng)建線程,會比較麻煩一點。 首先,我們要自定義一個類,對于這個類有兩點要求:

  • 必須繼承 threading.Thread 這個父類;

  • 必須覆寫 run 方法。
    【看個實例】

# 類方法
class MYThread(threading.Thread):

    def __init__(self,n):
        super().__init__()
        self.n = n

    def run(self):
        print("task",self.n)
        time.sleep(2)
        print("{} finished\n".format(self.n))

t1 = MYThread('t1')
t2 = MYThread('t2')


t = time.time()
t1.start()
t2.start()

# 調(diào)用者會等待該線程結(jié)束后,再執(zhí)行;

t2.join()

t1.join()

t1 = time.time()

print('main finished...')
print("線程所耗時間為:",t1 - t)

【輸出】

task t1
task t2
t1 finished
t2 finished


main finished...
線程所耗時間為: 2.0015668869018555
獲取線程的執(zhí)行結(jié)果
  • f1.result()
  • map()
  • as_completed
  • wait
  • add_done_callback

【關(guān)于 join() 函數(shù)】

import threading
import time
def run(n):
    print("task ",n )
    time.sleep(2)
    print("task done",n)

start_time = time.time()
for i in range(12):
    t = threading.Thread(target=run,args=("t-%s" %i ,))
    t.start()

print("----------all threads has finished...")
print("cost:",time.time() - start_time)

輸出:

task  t-0
task  t-1
task  t-2
task  t-3
task  t-4
task  t-5
task  t-6
task  t-7
task  t-8
task  t-9
task  t-10
task  t-11----------all threads has finished...
cost: 
0.001996278762817383
task donetask done t-2
 t-0
task done t-4task done task done t-3t-1

task done t-7
task done t-9task done 
task done task done t-8
t-5t-6

task donetask done  t-11
t-10

我們知道線程有 就緒、阻塞、運(yùn)行三種基本狀態(tài)。

  1. 就緒狀態(tài)是指線程具備運(yùn)行的所有條件,邏輯上可以運(yùn)行,在等待處理機(jī);

  2. 運(yùn)行狀態(tài)是指線程占有處理機(jī)正在運(yùn)行;

  3. 阻塞狀態(tài)是指線程在等待一個事件(如某個信號量),邏輯上不可執(zhí)行。

線程狀態(tài)轉(zhuǎn)換

關(guān)于【多線程】的小程序

from threading import Thread
import os, time

#計算密集型任務(wù)
def work():
    res = 0
    for i in range(100000000):
        res *= i

if __name__ == "__main__":
    l = []
    print("本計算機(jī)是",os.cpu_count(),"核 CPU")
    start = time.time()
    for i in range(4):
        p = Thread(target=work)  # 多進(jìn)程
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop = time.time()
    print("本計算機(jī)計算密集型任務(wù),多線程耗時 %s" % (stop - start))

輸出:

本計算機(jī)是 8 核 CPU
本計算機(jī)計算密集型任務(wù),多線程耗時 25.76108407974243

【關(guān)于is_alive()方法】:
可以用來判斷一個線程是否結(jié)束。

import threading
import time


def run(n):
    print("task ", n)
    time.sleep(2)
    print("task done", n)


start_time = time.time()
t_objs = []  # 存線程實例
for i in range(5):
    t = threading.Thread(target=run, args=("t-%s" % i,))
    t.start()
    t_objs.append(t)  # 為了不阻塞后面線程的啟動,不在這里join,先放到一個列表里

for t in t_objs:
    print(t.is_alive())

for t in t_objs:  # 循環(huán)線程實例列表,等待所有線程執(zhí)行完畢
    t.join()

for t in t_objs:
    print(t.is_alive())

print("----------all threads has finished...")
print("cost:", time.time() - start_time)

輸出:

task  t-0
task  t-1
task  t-2
task  t-3
task True
True
True
True
True
 t-4
task done task done t-1
t-0
task done t-4task done 
task done t-3t-2

False
False
False
False
False
----------all threads has finished...
cost: 2.0031514167785645

【續(xù)】:【python】多線程(高級篇):鎖 、GIL(全局鎖)、Queue隊列以及線程池http://m.itdecent.cn/p/04af68ab2c9b

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容