目錄
1.進(jìn)程和線程
1.1系統(tǒng)多任務(wù)機(jī)制
1.2進(jìn)程惦界、線程和協(xié)程
1.2.1進(jìn)程(process)
1.2.2線程(thread)
1.2.3串行倾芝、并行论衍、并發(fā)
2.多線程編程
2.1PYTHON中的多線程
2.1.1threading模塊屬性和方法
2.1.2thread類型屬性和方法
2.2函數(shù)式開發(fā)實(shí)現(xiàn)
2.2.1 線程狀態(tài)——join
2.2.2 線程狀態(tài)——daemon
2.2.3 線程管理——鎖【Lock/Rlock】
2.2.4 線程管理——死鎖【Dead Lock】
2.2.5 線程管理——實(shí)踐【Event】
2.2.6 油條的故事——Event實(shí)現(xiàn)
2.2.7 線程管理——條件【Condition】
2.2.8 生產(chǎn)者消費(fèi)者問題——Condition實(shí)現(xiàn)
2.2.9 線程管理——隊(duì)列【Queue】
2.2.10 生產(chǎn)者消費(fèi)者問題——Queue隊(duì)列實(shí)現(xiàn)
2.2.11 線程管理——其他
2.3 面向?qū)ο箝_發(fā)實(shí)現(xiàn)
2.3.1 面向?qū)ο竽莻€(gè)多線程基本語法
3.多進(jìn)程編程
3.1多進(jìn)程概述
3.2python多進(jìn)程開發(fā)
3.2.1multiprocessing
3.2.2多進(jìn)程的基礎(chǔ)操作
3.2.3 多進(jìn)程面向?qū)ο髮?shí)現(xiàn)
3.2.4 帶參數(shù)的多進(jìn)程:共享堰燎?獨(dú)占基矮?
3.2.5 多進(jìn)程的簡(jiǎn)化:內(nèi)置進(jìn)程池
3.2.6 多個(gè)進(jìn)程通信:multiprocessing.Manager
3.2.7多個(gè)進(jìn)程通信:multiprocessing.Queue
3.2.8 多個(gè)進(jìn)程通信:multiprocessing.Pipe
1.進(jìn)程和線程
1.1系統(tǒng)多任務(wù)機(jī)制
多任務(wù)操作機(jī)制的引入主要是在相同的硬件資源下怎么提高任務(wù)處理效率的淆储!多任務(wù)的處理機(jī)制可以在提升任務(wù)處理效率的基礎(chǔ)上,快速提升用戶體驗(yàn)家浇!
我們現(xiàn)實(shí)生活中無時(shí)無刻不在上演著多任務(wù)處理操作方式本砰,聽著音樂瞧著代碼,看著小說吃著大餐等等钢悲,都是多任務(wù)的體現(xiàn)点额,計(jì)算機(jī)在還原生活中功能處理流程的同事青团,也在還原生活中的多任務(wù)操作機(jī)制,計(jì)算機(jī)上的各種編程語言在多任務(wù)處理機(jī)制上都有非常友好的技術(shù)支持和實(shí)現(xiàn)方式
PYTHON本身也支持多任務(wù)處理咖楣,并且提供了如下的操作方式
多線程多任務(wù)處理機(jī)制
多進(jìn)程多任務(wù)處理機(jī)制
協(xié)程多任務(wù)處理機(jī)制
1.2進(jìn)程督笆、線程和協(xié)程
1.2.1 進(jìn)程(process)
進(jìn)程:計(jì)算機(jī)中一個(gè)程序在一個(gè)數(shù)據(jù)集上一次動(dòng)態(tài)執(zhí)行過程,主要包含三部分內(nèi)容
程序:描述進(jìn)程的功能以及處理流程
數(shù)據(jù)集:功能處理過程中需要的資源數(shù)據(jù)
進(jìn)程控制:嚴(yán)格控制進(jìn)程執(zhí)行過程中的各種狀態(tài)
通俗來說诱贿,一個(gè)進(jìn)程就是計(jì)算機(jī)上正在運(yùn)行的一個(gè)程序
一個(gè)軟件程序要運(yùn)行娃肿,需要將軟件依賴的數(shù)據(jù)加載到內(nèi)存中,通過CPU進(jìn)行運(yùn)算并按照程序定義的邏輯結(jié)構(gòu)進(jìn)行流程控制珠十,直到數(shù)據(jù)處理完成后程序退出料扰!
在程序?qū)嶋H執(zhí)行過程中,進(jìn)程只是分配需要的數(shù)據(jù)資源焙蹭,是程序的主題晒杈,在程序運(yùn)行時(shí)真正運(yùn)行的是線程,每個(gè)進(jìn)程至少會(huì)有一個(gè)線程
1.2.2 線程(Thread)
計(jì)算機(jī)中程序運(yùn)行的實(shí)際執(zhí)行者就是線程孔厉,線程又稱為輕量級(jí)進(jìn)程拯钻,是一個(gè)CPU的執(zhí)行單元,每個(gè)進(jìn)程至少會(huì)有一個(gè)主線程用于執(zhí)行程序
線程和進(jìn)程對(duì)比如下:
一個(gè)進(jìn)程可以有多個(gè)進(jìn)程撰豺,但是至少有一個(gè)主線程
一個(gè)線程只能屬于一個(gè)進(jìn)程
一個(gè)進(jìn)程中多個(gè)線程粪般,可以共享進(jìn)程中提供的數(shù)據(jù)
CPU運(yùn)算分配給線程,CPU上執(zhí)行運(yùn)算的是線程
線程是最小的運(yùn)行單元污桦,進(jìn)程是最小的資源管理單元
1.2.3串行亩歹、并行、并發(fā)
串行:就是傳統(tǒng)意義上的同步凡橱、順序的意思小作,按照一定的執(zhí)行步驟順序執(zhí)行每個(gè)環(huán)節(jié)
并行:就是傳統(tǒng)意義上的異步,同時(shí)的意思稼钩,同時(shí)執(zhí)行接收到的多個(gè)任務(wù)
并發(fā):同時(shí)接收到多個(gè)任務(wù)顾稀,同時(shí)執(zhí)行多個(gè)任務(wù),但是具體到某個(gè)時(shí)刻~只是在執(zhí)行一個(gè)任務(wù)变抽,只是在很短時(shí)間內(nèi)在多個(gè)任務(wù)之間切換础拨,模擬形成了多個(gè)任務(wù)同時(shí)執(zhí)行的現(xiàn)象
而大部分計(jì)算機(jī)中的因公用程序的執(zhí)行,一般都是并發(fā)執(zhí)行機(jī)制的多任務(wù)處理機(jī)制
因?yàn)镃PU的核心數(shù)目限制绍载,以前的CPU每個(gè)核心只有一個(gè)獨(dú)立的線程,也就是江湖傳言的單核單線程CPU滔蝉,只能執(zhí)行一個(gè)運(yùn)行線程击儡,為了能讓計(jì)算機(jī)實(shí)現(xiàn)多任務(wù)同時(shí)處理的機(jī)制,計(jì)算機(jī)就給CPU定義了時(shí)間片輪詢機(jī)制蝠引,讓CPU在很短的一個(gè)時(shí)間片執(zhí)行任務(wù)A阳谍,下一個(gè)時(shí)間片執(zhí)行任務(wù)B蛀柴、下一個(gè)時(shí)間片執(zhí)行任務(wù)C。這樣短時(shí)間的切換就會(huì)造成多個(gè)任務(wù)同時(shí)運(yùn)行的表象矫夯!
現(xiàn)在所說的CPU一般都是四核八線程鸽疾,或者或者八核十六線程之類的,其實(shí)就是表示了CPU在同一時(shí)間可以同時(shí)執(zhí)行多少個(gè)線程程序训貌,也就是CPU級(jí)別的多線程運(yùn)行機(jī)制制肮。
但是PYTHON為了保證多任務(wù)機(jī)制下的共享數(shù)據(jù)的安全性和完整性,Cpython官方解釋器內(nèi)置了一個(gè)GIL(Global Interceptor Lock:全局解釋器鎖)递沪,只允許在同一時(shí)間內(nèi)CPU只能執(zhí)行一個(gè)線程豺鼻,所以在PYTHON的官方解釋器下,所謂多線程是多線程并發(fā)機(jī)制并不是多線程并行機(jī)制款慨!
2.多線程編程
在python2中提供了標(biāo)準(zhǔn)模塊thread和threading支持多線程的并發(fā)編程儒飒,但是隨著并發(fā)編程的實(shí)際使用操作過程,thread模塊國(guó)語底層的控制方式對(duì)于并發(fā)編程的新手來說不是很友好檩奠,要求多線程的程序開發(fā)邏輯思維清晰同時(shí)又具備大量開發(fā)經(jīng)驗(yàn)的情況下桩了,可以控制的非常精細(xì)
python3中將thread模塊進(jìn)行了規(guī)范內(nèi)置,更名為_thread埠戳,友好的提醒如果你不是并發(fā)編程的骨灰級(jí)愛好者圣猎,請(qǐng)不要輕易闡釋使用_thread進(jìn)行操作,而胡思推薦使用操作更加靈活使用更加簡(jiǎn)潔的threading模塊進(jìn)行并發(fā)編程的處理乞而。
_thread模塊多線程并發(fā)任務(wù)的簡(jiǎn)單實(shí)現(xiàn)如下:
import _thread,time
#定義函數(shù)送悔,函數(shù)中執(zhí)行循環(huán)遍歷指定的循環(huán)
def test(num):
for i in range(num):
print(_thread.get_ident(),":",i)
#通過_thread.start_new_thread()啟動(dòng)兩個(gè)線程,分別執(zhí)行test函數(shù)
_thread_start_new_thread(test,(2,))
_thread_start_new_thread(test,(3,))
#讓主線程休眠3s爪模,等待子線程執(zhí)行結(jié)束
time.sleep(3)
2.1 PYHTON中的多線程
官方推薦的_threading模塊的多線程并發(fā)編程機(jī)制欠啤,結(jié)合是下流行的面向過程、面向獨(dú)享的編程處理模式屋灌,主要有兩種操作方式
(1)函數(shù)式的線程創(chuàng)建方式洁段,適合面向過程程序的并發(fā)編程實(shí)現(xiàn)
(2)面向?qū)ο蟮膭?chuàng)建方式,適合面向?qū)ο蟪绦虻牟l(fā)編程實(shí)現(xiàn)
’
2.1.1threading模塊的屬性和方法
Thread 線程類共郭,用于創(chuàng)建和管理線程
Event 事件類祠丝,用于線程同步
Condition 條件類,用于線程同步
Lock/Rlock 鎖類除嘹,用于線程同步
Timer 延時(shí)線程写半,一批能夠與在一定事件后執(zhí)行一個(gè)函數(shù)
Semaphore/BoundedSemaphore 信號(hào)量類,用于線程同步
active_count()/activeCount() 獲取當(dāng)前alive狀態(tài)的所有線程數(shù)量
current_thread()/currentThread() 獲取當(dāng)期正在執(zhí)行的線程對(duì)象
get_ident() 獲取運(yùn)行中程序當(dāng)前線程的唯一編號(hào)
enumerate() 獲取所有alive狀態(tài)線程列表
local 線程局部數(shù)據(jù)類
stack_size([size]) 獲取線程占用內(nèi)存棧的大小
main_thread 獲取主線程
2.1.2 Thread 類型屬性和方法
__init__(group,target,name,args,kwargs) 構(gòu)造方法尉咕,創(chuàng)建線程類型
is_alive()/isAlive() 判斷當(dāng)前線程是否alive狀態(tài)
run() 線程執(zhí)行方法叠蝇,自定義線程必須重寫該函數(shù)
start() 線程啟動(dòng)方法
join(【timeout = None】) 線程獨(dú)占,等待當(dāng)前線程運(yùn)行結(jié)束或者超時(shí)
ident 標(biāo)識(shí)當(dāng)前線程的唯一編號(hào)
name 當(dāng)前線程名稱
daemon 布爾值年缎,判斷當(dāng)前線程是否守護(hù)線程
2.2 函數(shù)式開發(fā)實(shí)現(xiàn)
通過threading 模塊的Thread函數(shù)們可以實(shí)現(xiàn)多線程程序的運(yùn)行
案例需求:火車站窗口售票
(1)單線程實(shí)現(xiàn)模式:相當(dāng)于只有一個(gè)窗口售票
import time
#總票數(shù)
count = 10
def sale_tickle():
global count
while count >0:
print("售出一張票”悔捶,count)
count -= 1
time.sleep(0.5)
else:
print("售票結(jié)束铃慷,沒有票了”)
if __name__ == "__main__"
sale_tickle()
多線程售票:相當(dāng)于多個(gè)窗口同時(shí)售票
import time
#總票數(shù)
count = 10
def sale_tickle():
global count
while count >0:
print("售出一張票”,count)
count -= 1
time.sleep(0.5)
else:
print("售票結(jié)束蜕该,沒有票了”)
if __name__ == "__main__"
#定義多個(gè)線程(窗口)
t1 = threading.Thread(name = "窗口1"犁柜,target = sale_tickle)
t2 = threading.Thread(name = "窗口2",target = sale_tickle)
t3 = threading.Thread(name = "窗口3堂淡,target = sale_tickle)
t4= threading.Thread(name = "窗口4"馋缅,target = sale_tickle)
t5 = threading.Thread(name = "窗口5",target = sale_tickle)
#啟動(dòng)五個(gè)串口同時(shí)售票
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
#程序運(yùn)行要比單線程運(yùn)行節(jié)省好幾倍的時(shí)間淤齐,這就是多線程的魅力股囊!
2.2.1線程狀態(tài)_join
join:線程的join狀態(tài)是獨(dú)占模式,當(dāng)前線程獨(dú)占CPU運(yùn)行單元更啄,必須等待當(dāng)前線程執(zhí)行完成或者超時(shí)之后稚疹,才能運(yùn)行其他線程
import time
#總票數(shù)
count = 10
def sale_tickle():
global count
while count >0:
print("售出一張票”,count)
count -= 1
time.sleep(0.5)
else:
print("售票結(jié)束祭务,沒有票了”)
if __name__ == "__main__"
#定義多個(gè)線程(窗口)
t1 = threading.Thread(name = "窗口1"内狗,target = sale_tickle)
t2 = threading.Thread(name = "窗口2",target = sale_tickle)
t3 = threading.Thread(name = "窗口3义锥,target = sale_tickle)
t4= threading.Thread(name = "窗口4"柳沙,target = sale_tickle)
t5 = threading.Thread(name = "窗口5",target = sale_tickle)
#啟動(dòng)五個(gè)串口同時(shí)售票
t1.start()
#線程t1調(diào)用join拌倍,獨(dú)占模式運(yùn)行赂鲤,等待t1線程運(yùn)行結(jié)束或者超時(shí),才能繼續(xù)運(yùn)行其他線程
t1.join()
t2.start()
t3.start()
t4.start()
t5.start()
#程序運(yùn)行要比單線程運(yùn)行節(jié)省好幾倍的時(shí)間柱恤,這就是多線程的魅力数初!
2.2.2線程狀態(tài)-daemon
線程對(duì)象的daemon屬性用于標(biāo)識(shí)某個(gè)線程是否守護(hù)線程
守護(hù)線程的意義在于~跟主線程之間山無陵天地合,同生共死梗顺,一旦主線程執(zhí)行退出泡孩,無論守護(hù)線程是否執(zhí)行完成,都會(huì)直接退出寺谤!
2.2.3線程管理—鎖【Lock/Rlock】
多線程程序在運(yùn)行過程中仑鸥,由于多個(gè)線程訪問的是同一部分?jǐn)?shù)據(jù),很容易會(huì)造成共享數(shù)據(jù)訪問沖突的現(xiàn)象变屁,如果一旦出現(xiàn)沖突程序就會(huì)出現(xiàn)執(zhí)行結(jié)果不符合期望的結(jié)果
此時(shí)共享數(shù)據(jù)的修改操作眼俊,在多線程的情況下,是需要通過鎖定的方式進(jìn)行獨(dú)占修改的敞贡!就如同入廁一樣泵琳,當(dāng)多個(gè)人[線程】在執(zhí)行程序,修改數(shù)據(jù)【入廁】時(shí)誊役,每個(gè)線程在操作過程中都需要鎖定這一部分?jǐn)?shù)據(jù)【廁所】获列,直到數(shù)據(jù)處理完成之后解鎖,下一個(gè)線程才能進(jìn)行操作
python中提供了兩種線程鎖的操作
(1)同步鎖/互斥鎖:lock
(2)可重用鎖 :Rlock
鎖的操作主要是獲取鎖和釋放鎖兩種
(1)acquire()獲取鎖蛔垢,上鎖击孩,鎖定
(2)release()釋放鎖,開鎖鹏漆,解鎖
2.2.4 線程管理-死鎖【Dead Lock】
線程鎖固然功能強(qiáng)大巩梢,可以管理多個(gè)線程之間的共享數(shù)據(jù)問題, 但是同時(shí)它的強(qiáng)大也帶了了比較糾結(jié)的問題艺玲,需要開發(fā)人員對(duì)于鎖定的數(shù)據(jù)有一個(gè)良好的人認(rèn)知括蝠,否則特別容易造成死鎖的現(xiàn)象,比較著名的哲學(xué)家吃飯問題就是死鎖的典型代表
由于計(jì)算機(jī)運(yùn)算速度較快饭聚,所有有兩種方案可以將問題放大
(1)給執(zhí)行函數(shù)添加休眠時(shí)間
(2)添加線程數(shù)量
死鎖并不是每次都會(huì)出現(xiàn)的忌警,而是程序在執(zhí)行過程中,根據(jù)系統(tǒng)CPU時(shí)間片的切換機(jī)制恰好遇到了重復(fù)上鎖的情況秒梳,就會(huì)死鎖法绵。
實(shí)際項(xiàng)目開發(fā)過程中,一定要注意死鎖情況的影響
這樣的情況可以通過可重用鎖Rlock進(jìn)行鎖定處理
pyhton中的互斥鎖酪碘,只有兩種狀態(tài)朋譬,locked和unlocked,如果一旦重復(fù)上鎖就會(huì)死鎖兴垦,但是可重用所Rlock 徙赢,在鎖定的基礎(chǔ)上提供了一個(gè)計(jì)數(shù)器counter,可以計(jì)算上鎖的次數(shù)然后通過release()解鎖時(shí)就會(huì)重新運(yùn)算計(jì)數(shù)器探越,等待計(jì)數(shù)器清零時(shí)所有鎖全都釋放了狡赐!
2.2.5 線程管理—時(shí)間【Event】
線程鎖解決了多個(gè)線程訪問共享數(shù)據(jù)時(shí)沖突的問題,如果多個(gè)線程之間需要通信應(yīng)該怎么解決呢扶关?此時(shí)就需要用到多個(gè)線程之間的可以用于互相通信的處理對(duì)象了阴汇,該處理對(duì)象必須滿足如下基本條件:
(1)該對(duì)象能同時(shí)被多個(gè)線程訪問
(2)該對(duì)象可以被標(biāo)記不同的狀態(tài)
(3)該對(duì)象可以用于控制線程等待|運(yùn)行之間的切換
pyhton提供了一個(gè)事件對(duì)象Event,可以基本滿足上述條件节槐,完成線程之間的通信
set() 添加一個(gè)標(biāo)記狀態(tài)
isSet()/is_set() 檢查事件對(duì)象是否被標(biāo)記
clear() 清除標(biāo)記狀態(tài)
wait() 事件對(duì)象操作的當(dāng)前線程等待搀庶,直到該對(duì)象被標(biāo)記狀態(tài)
2.2.6 油條的故事- Event實(shí)現(xiàn)
需求:一個(gè)冬天的早晨,顧客去小攤販那里買油條铜异,由于油條都是現(xiàn)炸哥倔,所以顧客需要等待小攤販生產(chǎn)油條,小攤販生產(chǎn)好油條后顧客可以進(jìn)餐揍庄,結(jié)束后打招呼離開
分析:這里有兩個(gè)線程咆蒿,小攤販線程和顧客線程,顧客線程運(yùn)行開始必須等待,小攤販線程工作生產(chǎn)油條沃测,當(dāng)油條生產(chǎn)之后喚醒顧客線程缭黔,此時(shí)小攤販線程等待,顧客就餐完畢之后準(zhǔn)備離開蒂破,喚醒小攤販結(jié)賬走人馏谨!
兩個(gè)線程的通信:事件對(duì)象:threading.Event
set()添加標(biāo)記
wait()線程等待-如果當(dāng)前事件對(duì)象被標(biāo)記~繼續(xù)運(yùn)行
clear()清除標(biāo)記
import threading,time
#定義事件對(duì)象
event = threading.Event()
def xiao_fan():
print("XF,炸油條.......")
time.sleep(2)
#添加標(biāo)記
event.set()
event.clear()
print("XF, 賣油條“)
event.wait()
print("XF:結(jié)賬完畢,謝謝光臨”)
def gu_ke():
#線程等待~等待事件對(duì)象被標(biāo)記
event.wait()
print("GK:買油條“)
print("GK:吃油條”)
time.sleep(2)
if __name__ == "__main__":
xf = threading.Thread(target = xiao_fan)
gk = threading.Thread(target = gu_ke)
xf.start()
gk.start()
2.2.7 線程管理-條件【Condition】
線程條件Condition對(duì)象附迷,也是多
線程并發(fā)模式下一種線程之間通信的友好支持
在某些情況下惧互,我們需要多個(gè)線程在運(yùn)行過程中根據(jù)實(shí)際操作情況,不同功能的線程在滿足對(duì)應(yīng)的條件時(shí)等待喇伯、啟動(dòng)兩種狀態(tài)之間進(jìn)行切換
如經(jīng)典的線程間通信問題:生產(chǎn)者消費(fèi)者問題
生產(chǎn)者負(fù)責(zé)上生產(chǎn)食物喊儡,將食物存儲(chǔ)在列表中;消費(fèi)者負(fù)責(zé)消費(fèi)稻据,也就是從列表中刪除數(shù)據(jù)艾猜;這里的存儲(chǔ)食物的列表,我們限制了長(zhǎng)度攀甚,最多容納20個(gè)食物數(shù)據(jù)
此時(shí)就會(huì)出現(xiàn)這樣的問題箩朴,如果列表中的食物已經(jīng)達(dá)到20;那么所有的生產(chǎn)者線程不能繼續(xù)生產(chǎn)食物了秋度,必須處于等待狀態(tài)炸庞,等待消費(fèi)者消費(fèi)了食物之后再次生產(chǎn)
同理如果列表中的食物為空了,所有的消費(fèi)者也就不能吃食物了荚斯,必須處于等待狀態(tài)埠居,等待生產(chǎn)者生產(chǎn)了食物之后才能消費(fèi)
Conditon()對(duì)象的屬性和方法
acquire() 鎖定
release() 解鎖
wait() 釋放鎖,同時(shí)阻塞當(dāng)前線程事期,等待被喚醒
wait_for() 釋放鎖滥壕,同時(shí)阻塞當(dāng)前線程,等待被喚醒
notify() 喚醒
notify_all() 喚醒所有等待condition條件的線程
2.2.8 生產(chǎn)者消費(fèi)者問題-Condition 實(shí)現(xiàn)
需求:生產(chǎn)者消費(fèi)者問題兽泣,描述的是多個(gè)線程之間的通信處理方式和手段绎橘。多個(gè)生產(chǎn)者線程生產(chǎn)食品放到指定的食品容器中,并喚醒所有的消費(fèi)者線程開始就餐如果食品容器容量飽和唠倦,則所有生產(chǎn)者線程等待
多個(gè)消費(fèi)者線程在指定的視屏容器中獲取食物就餐称鳞,并喚醒所有的生產(chǎn)者線程開始生產(chǎn),如果食品容器中沒有任何視屏了稠鼻,則所有消費(fèi)者線程等待
import threading,time,random
#定義食物列表
foods = list()
#創(chuàng)建一個(gè)線程條件對(duì)象
con = threading.Conditon()
def product():
while True:
time.sleep(0.5)
con.acquire()
if len(foods)<20:
_no = random.randint(0,20)
print("生產(chǎn)者{}生產(chǎn)了:format(threading.current_thread().getName(),_no)
foods.append(_no)
print("PRO--",len(foods))
con.notify()
else:
con.wait()
print("生產(chǎn)者{}----等待”冈止。format(threading.current_thread().getName()))
con.release()
def consumer():
while True:
time.sleep(0.5)
con.acquire()
if len(foods) >0:
_no = foods.pop()
print("消費(fèi)者{}消費(fèi)了".format(threading.current_thread().getName()), _no)
print("CUS--", len(foods))
con.notify()
else:
con.wait()
print("消費(fèi)者{}-----等待”.format(threading.current_thread().getName()))
con.release()
if __name__ == "__main__":
#創(chuàng)建多個(gè)生產(chǎn)者線程
for i in range(5):
p = threading.Thread(name = "_p" + str(i),target = product)
p.start
#創(chuàng)建多個(gè)消費(fèi)者線程
for j in range(2):
c = threading.Thread(name = "_c" + str(j),target = consumer)
c.start()
2.2.9 線程管理-隊(duì)列【Queue】
多線程并發(fā)編程的重點(diǎn),是線程之間共享數(shù)據(jù)的訪問問題和線程之間的通信問題
為了解決線程之間數(shù)據(jù)共享問題候齿,python提供了一個(gè)數(shù)據(jù)類型【隊(duì)列】可以用于在多線程并發(fā)模式下熙暴,安全的訪問數(shù)據(jù)而不會(huì)造成數(shù)據(jù)共享沖突
pyhton中queue模塊提供的隊(duì)列類型Queue的操作模式如下
put(【timeout = None】) 想隊(duì)列中添加數(shù)據(jù)闺属,隊(duì)列如果滿了,一直阻塞知道超市或者隊(duì)列中有數(shù)據(jù)被刪除之后添加成功
get(【timeout = None】)從隊(duì)列中獲取數(shù)據(jù)周霉,如果隊(duì)列為空掂器,一直阻塞知道超時(shí)或者隊(duì)列中添加數(shù)據(jù)之后獲取成功
2.3面向?qū)ο箝_發(fā)實(shí)現(xiàn)
pyhton人性化的提供了使用與更加強(qiáng)大場(chǎng)合的多線程并發(fā)編程
面向?qū)ο蟮牟僮髂J剑宲ython的多線程并發(fā)更加優(yōu)秀
2.3.1面向?qū)ο蠖嗑€程基本語法
面向?qū)ο蟮亩嗑€程诗眨,主要是讓自定義類型派生自threading.Thread類
重寫Thread類型的run()方法唉匾,然后創(chuàng)建自定義線程類的對(duì)象之后孕讳,調(diào)用start()方法啟動(dòng)
3.多進(jìn)程編程
3.1多進(jìn)程概述
進(jìn)程是正在執(zhí)行中國(guó)的應(yīng)用程序匠楚,一個(gè)進(jìn)程包含了該應(yīng)用程序的所有信息,如加載數(shù)據(jù)內(nèi)存空間厂财、代碼芋簿、程序數(shù)據(jù)、對(duì)象句柄璃饱、執(zhí)行單元等等与斤,一個(gè)應(yīng)用程序根據(jù)其功能的多樣性,可以通過多個(gè)進(jìn)程并發(fā)的形式來實(shí)現(xiàn)
計(jì)算機(jī)中多線程的操作已經(jīng)可以實(shí)現(xiàn)多任務(wù)的處理機(jī)制了荚恶,但是如果實(shí)際到多核CPU或者多個(gè)CPU的硬件主機(jī)撩穿,多進(jìn)程并發(fā)編程的實(shí)現(xiàn)能比多線程并發(fā)機(jī)制更加有效的利用和發(fā)揮硬件資源優(yōu)勢(shì)
3.2pyhton多進(jìn)程開發(fā)
3.2.1multiprocessing
python內(nèi)建標(biāo)準(zhǔn)模塊multiprocessing 對(duì)多進(jìn)程并發(fā)編程提供了良好的支持,通過該模塊的Process進(jìn)程類型谒撼,可以很方便的創(chuàng)建和管理多個(gè)進(jìn)程食寡,通過該模塊提供的Lock|Rlock進(jìn)程鎖類型、Event事件類型廓潜。Condition條件類型等等也可以很方便的完成進(jìn)程間同步操作
和多線程的操作方式類似抵皱,多進(jìn)程的實(shí)現(xiàn)方式也提供了面向過程的實(shí)現(xiàn)和面向?qū)ο蟮膶?shí)現(xiàn),同時(shí)多進(jìn)程的本地?cái)?shù)據(jù)共享和通信模式也非常的類似多線程編程
multiprocessing常見屬性和方法
Process 進(jìn)程類型辩蛋,用于創(chuàng)建和管理進(jìn)程
Lock/Rlock 進(jìn)程互斥鎖/重用鎖呻畸,用于進(jìn)程同步
Event 進(jìn)程事件類型,用于進(jìn)程同步
Condition 進(jìn)程條件類型悼院,用于進(jìn)程同步
Queue 進(jìn)程隊(duì)列類型伤为,用于多進(jìn)程數(shù)據(jù)共享
Manager 進(jìn)程管理類型,用于多進(jìn)程數(shù)據(jù)共享
listener|Client 進(jìn)程監(jiān)聽|客戶端据途,基于網(wǎng)絡(luò)多進(jìn)程之間的數(shù)據(jù)共享
3.2.2多進(jìn)程的基礎(chǔ)操作
main方法運(yùn)行的是主進(jìn)程绞愚,通過multiprocessing創(chuàng)建的子進(jìn)程是由主進(jìn)程產(chǎn)生的!
3.2.3對(duì)進(jìn)程面向?qū)ο髮?shí)現(xiàn)
多進(jìn)程的面向?qū)ο蟮膶?shí)現(xiàn)方式類似多線程的操作模式
自定義進(jìn)程類型昨凡,繼承系統(tǒng)進(jìn)程標(biāo)準(zhǔn)類型multiprocessing.Process
重寫父類的run()方法爽醋,在方法中定義執(zhí)行代碼
在使用時(shí)創(chuàng)建該自定義進(jìn)程類型的對(duì)象,調(diào)用對(duì)象的start()方法啟動(dòng)一個(gè)新的進(jìn)程
3.2.4帶參數(shù)的多進(jìn)程:共享便脊?獨(dú)占蚂四?
多線程的操作模式下我們的全局變量是多個(gè)線程共享的,所以多線程并發(fā)模式下對(duì)于數(shù)據(jù)的修改非常危險(xiǎn),那么多進(jìn)程模式下數(shù)據(jù)的處理應(yīng)該是什么樣的呢遂赠?
通過兩種方式來觀察多進(jìn)程模式下數(shù)據(jù)的處理
(1)全局變量的數(shù)據(jù)
(2)參數(shù)數(shù)據(jù)
3.2.5 多進(jìn)程的簡(jiǎn)化:內(nèi)置進(jìn)程池
多進(jìn)程的操作在實(shí)際應(yīng)用中也是非常多的久妆,但是純底層的代碼開發(fā)控制并發(fā)也是一件非常繁瑣的事情,所以就出現(xiàn)了面向過程多進(jìn)程并發(fā)的優(yōu)化操作方式:進(jìn)程池pool
通過進(jìn)程池pool可以快速創(chuàng)建多個(gè)進(jìn)程執(zhí)行指定函數(shù)跷睦,完成高并發(fā)處理操作
(1)Pool對(duì)象的屬性和方法
apply(func,args) 傳遞參數(shù)args并執(zhí)行函數(shù)func筷弦,同時(shí)阻塞當(dāng)前進(jìn)程知道該函數(shù)執(zhí)行完成,函數(shù)func智慧在進(jìn)程池中的一個(gè)進(jìn)程中運(yùn)行
apply_async(func,args,callback,error_callback)
傳遞參數(shù)args并執(zhí)行函數(shù)func抑诸,該方法不會(huì)形成阻塞烂琴,函數(shù)執(zhí)行完成之后可以通過結(jié)果對(duì)象的get(方法獲取結(jié)果,如果結(jié)果對(duì)象可用是會(huì)自動(dòng)調(diào)用callback指定的函數(shù)蜕乡,如果結(jié)果對(duì)象調(diào)用失敗是會(huì)自動(dòng)調(diào)用error_callback指定的函數(shù)
close() Pool進(jìn)程池的底層工作機(jī)制是向進(jìn)程池提交任務(wù)產(chǎn)生工作進(jìn)程執(zhí)行該方法是主動(dòng)停止給進(jìn)程池提交任務(wù)奸绷,并等待所有提交任務(wù)執(zhí)行完成退出
terminate()立即結(jié)束該進(jìn)程,當(dāng)進(jìn)程池對(duì)象被回收時(shí)自動(dòng)調(diào)用該方法
join()等待工作進(jìn)程退出层玲,再次之間必須調(diào)用close()或者terminate
3.2.6 多個(gè)進(jìn)程通信:multiprocessing.Manager
不同進(jìn)程之間的數(shù)據(jù)通信号醉,涉及到核心的數(shù)據(jù)共享問題,主要由python中提供的內(nèi)建模塊multiprocessing.Manager類型實(shí)現(xiàn)辛块,該類型內(nèi)置了大量的用于數(shù)據(jù)共享的操作
multiprocessing.Manager 常見屬性和方法
Array 內(nèi)置進(jìn)程間共享數(shù)組類型
Queue 內(nèi)置進(jìn)程間共享隊(duì)列類型
list() 內(nèi)置進(jìn)程間共享列表類型
dict() 內(nèi)置進(jìn)程間共享字典類型
Value 內(nèi)置進(jìn)程間共享值類型
Barrier 進(jìn)程同步類型
BoundedSemaphore|Semaphore 進(jìn)程信號(hào)量類型
Lock|Rlock 進(jìn)程互斥鎖/重用鎖
Event 進(jìn)程同步時(shí)間類型
Conditon 進(jìn)程同步條件類型
3.2.7 多個(gè)進(jìn)程通信:multiprocessing.Queue
多個(gè)進(jìn)程之間的痛惜操作畔派,數(shù)據(jù)的床底在pyhotn中的multiprocesisng模塊中提供了一個(gè)專門用于多進(jìn)程之間進(jìn)行數(shù)據(jù)傳遞的隊(duì)列:Queue
multiprocessing.Queue常見屬性和方法
put(data【,timeout= None】) 添加一個(gè)數(shù)據(jù)到隊(duì)列中
put_nowait(data) 添加一個(gè)數(shù)據(jù)到隊(duì)列中润绵,非阻塞模式
get(【timeout = None】) 從隊(duì)列中獲取一個(gè)數(shù)據(jù)
get_nowait() 從隊(duì)列中獲取一個(gè)數(shù)據(jù)线椰,非阻塞模式
full() 判斷隊(duì)列是否已滿
empty() 判斷隊(duì)列是否已空
close() 關(guān)閉隊(duì)列
qsize() 獲取隊(duì)列中的元素?cái)?shù)量
3.2.8 多個(gè)進(jìn)程通信:multiprocessing.pipe
python為了更加友好的多個(gè)進(jìn)程之間的數(shù)據(jù)通信操作,提供了一個(gè)管道類型專門用于進(jìn)程之間的協(xié)作:multipricessing.pipe
multiprocessing.pipe 常見屬性和方法
__init__(duplex = True) 初始化方法授药,返回兩個(gè)數(shù)據(jù)conn1,conn2分別表示管道的兩端士嚎,默認(rèn)是雙向通信,如果duplex = False悔叽, conn1只能接受消息莱衩, conn2只能發(fā)送消息
send