線程
什么是線程
(1)線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位型将。
(2)它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位荐虐。
(3)一條線程指的是進(jìn)程中一個(gè)單一順序的控制流七兜,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù)福扬。
(4)一個(gè)線程是一個(gè)execution context(執(zhí)行上下文)腕铸,即一個(gè)cpu執(zhí)行時(shí)所需要的一串指令。
【重點(diǎn)】一個(gè)程序運(yùn)行后至少有一個(gè)進(jìn)程铛碑,一個(gè)進(jìn)程中可以包含多個(gè)線程狠裹;
線程的工作方式
CPU會(huì)給你一個(gè)在同一時(shí)間能夠做多個(gè)運(yùn)算的幻覺,實(shí)際上它在每個(gè)運(yùn)算上只花了極少的時(shí)間汽烦,本質(zhì)上CPU同一時(shí)刻只干了一件事涛菠。它能這樣做就是因?yàn)樗忻總€(gè)運(yùn)算的execution context。就像你能夠和你朋友共享同一本書一樣撇吞,多任務(wù)也能共享同一塊CPU俗冻。
啟動(dòng)多個(gè)線程(函數(shù)實(shí)現(xiàn))
Python提供了一個(gè)內(nèi)置模塊 threading.Thread,可以很方便地讓我們創(chuàng)建多線程牍颈。 threading.Thread() 一般接收兩個(gè)參數(shù):
線程函數(shù)名:要放置線程讓其后臺(tái)執(zhí)行的函數(shù)迄薄,由我們自已定義,注意不要加()颂砸;
線程函數(shù)的參數(shù):線程函數(shù)名所需的參數(shù)噪奄,以元組的形式傳入。若不需要參數(shù)人乓,可以不指定勤篮。
【舉個(gè)例子】:
import threading
import time
def run(n):
print("task ",n )
time.sleep(2)
# run("t1")
# run("t2")
t1 = threading.Thread(target=run,args=("t1",))#生成一個(gè)線程實(shí)例
t2 = threading.Thread(target=run,args=("t2",))
t1.start()
t2.start()
【輸出】:
task t1
task t2
【解釋】由于每個(gè)方法都有單獨(dú)的進(jìn)程,會(huì)同時(shí)開始執(zhí)行色罚,上面代碼會(huì)同時(shí)輸出
啟動(dòng)多個(gè)線程(類實(shí)現(xiàn))
相比較函數(shù)而言碰缔,使用類創(chuàng)建線程,會(huì)比較麻煩一點(diǎn)戳护。 首先金抡,我們要自定義一個(gè)類瀑焦,對(duì)于這個(gè)類有兩點(diǎn)要求:
必須繼承 threading.Thread 這個(gè)父類;
必須覆寫 run 方法梗肝。
【看個(gè)實(shí)例】
# 類方法
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)用者會(huì)等待該線程結(jié)束后榛瓮,再執(zhí)行;
t2.join()
t1.join()
t1 = time.time()
print('main finished...')
print("線程所耗時(shí)間為:",t1 - t)
【輸出】
task t1
task t2
t1 finished
t2 finished
main finished...
線程所耗時(shí)間為: 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)是指線程在等待一個(gè)事件(如某個(gè)信號(hào)量)凫乖,邏輯上不可執(zhí)行。
關(guān)于【多線程】的小程序
from threading import Thread
import os, time
#計(jì)算密集型任務(wù)
def work():
res = 0
for i in range(100000000):
res *= i
if __name__ == "__main__":
l = []
print("本計(jì)算機(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ì)算機(jī)計(jì)算密集型任務(wù)弓颈,多線程耗時(shí) %s" % (stop - start))
輸出:
本計(jì)算機(jī)是 8 核 CPU
本計(jì)算機(jī)計(jì)算密集型任務(wù)帽芽,多線程耗時(shí) 25.76108407974243
【關(guān)于is_alive()方法】:
可以用來判斷一個(gè)線程是否結(jié)束。
import threading
import time
def run(n):
print("task ", n)
time.sleep(2)
print("task done", n)
start_time = time.time()
t_objs = [] # 存線程實(shí)例
for i in range(5):
t = threading.Thread(target=run, args=("t-%s" % i,))
t.start()
t_objs.append(t) # 為了不阻塞后面線程的啟動(dòng)翔冀,不在這里join嚣镜,先放到一個(gè)列表里
for t in t_objs:
print(t.is_alive())
for t in t_objs: # 循環(huán)線程實(shí)例列表,等待所有線程執(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】多線程(高級(jí)篇):鎖 橘蜜、GIL(全局鎖)、Queue隊(duì)列以及線程池:http://www.reibang.com/p/04af68ab2c9b