線程
什么是線程
(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)。
就緒狀態(tài)是指線程具備運(yùn)行的所有條件,邏輯上可以運(yùn)行,在等待處理機(jī);
運(yùn)行狀態(tài)是指線程占有處理機(jī)正在運(yùn)行;
阻塞狀態(tài)是指線程在等待一個事件(如某個信號量),邏輯上不可執(zhí)行。

關(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