進(jìn)程、進(jìn)程的使用、進(jìn)程注意點(diǎn)、進(jìn)程間通信-Queue、進(jìn)程池Pool、進(jìn)程與線程對(duì)比、文件夾拷貝器-多任務(wù)
1.進(jìn)程介紹
多進(jìn)程本質(zhì)是創(chuàng)建一個(gè)進(jìn)程默認(rèn)創(chuàng)建一個(gè)線程,任務(wù)本身是由線程完成的。多進(jìn)程可以處理多任務(wù),但是每創(chuàng)建一個(gè)進(jìn)程都要向系統(tǒng)索要運(yùn)行資源,相比線程來(lái)說(shuō)資源占用比較多成本比較大
<1>進(jìn)程的概念
進(jìn)程:通俗理解一個(gè)運(yùn)行的程序或者軟件,進(jìn)程是操作系統(tǒng)資源分配的基本單位。
注意:一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程,多進(jìn)程可以完成多任務(wù).
<2>進(jìn)程的狀態(tài)
工作中,任務(wù)數(shù)往往大于cpu的核數(shù),即一定有一些任務(wù)正在執(zhí)行,而另外一些任務(wù)在等待cpu進(jìn)行執(zhí)行,因此導(dǎo)致了有不同的狀態(tài)
? 就緒態(tài):運(yùn)行的條件都已經(jīng)滿足,正在等待cpu執(zhí)行
? 執(zhí)行態(tài):cpu正在執(zhí)行其功能
? 等待態(tài):等待某些條件滿足,例如一個(gè)程序sleep了,此時(shí)就處于等待態(tài)
小結(jié):
一個(gè)進(jìn)程默認(rèn)有一個(gè)線程,進(jìn)程里面可以創(chuàng)建線程,線程是依附在進(jìn)程里面的,沒(méi)有進(jìn)程就沒(méi)有線程。
2.進(jìn)程的使用
<1>多進(jìn)程完成多任務(wù)
? 導(dǎo)入進(jìn)程模塊
import multiprocessing
<2>Process進(jìn)程類(lèi)的語(yǔ)法結(jié)構(gòu)如下:
Process([group [, target [, name [, args [, kwargs]]]]])
? group:指定進(jìn)程組,目前只能使用None
? target:執(zhí)行的目標(biāo)任務(wù)名
? name:進(jìn)程名字
? args:以元組方式給執(zhí)行任務(wù)傳參
? kwargs:以字典方式給執(zhí)行任務(wù)傳參
Process創(chuàng)建的實(shí)例對(duì)象的常用方法:
? start():?jiǎn)?dòng)子進(jìn)程實(shí)例(創(chuàng)建子進(jìn)程)
? join([timeout]):是否等待子進(jìn)程執(zhí)行結(jié)束,或等待多少秒
? terminate():不管任務(wù)是否完成,立即終止子進(jìn)程
Process創(chuàng)建的實(shí)例對(duì)象的常用屬性:
? name:當(dāng)前進(jìn)程的別名,默認(rèn)為Process-N,N為從1開(kāi)始遞增的整數(shù)
? pid:當(dāng)前進(jìn)程的pid(進(jìn)程號(hào))
<3>多進(jìn)程完成多任務(wù)代碼
import multiprocessing
import time
def run_proc():
? ? """子進(jìn)程要執(zhí)行的代碼"""
? ? while True:
? ? ? ? print("----2----")
? ? ? ? time.sleep(1)
if __name__=='__main__':
? ? # 創(chuàng)建子進(jìn)程
? ? sub_process = multiprocessing.Process(target=run_proc)
? ? # 啟動(dòng)子進(jìn)程
? ? sub_process.start()
? ? while True:
? ? ? ? print("----1----")
? ? ? ? time.sleep(1)
<4>獲取當(dāng)前進(jìn)程、當(dāng)前進(jìn)程pid、父進(jìn)程pid(paternal pid)、殺死對(duì)應(yīng)的進(jìn)程
? 獲取當(dāng)前進(jìn)程
? ? ? multiprocessing.current_process()
? 獲取當(dāng)前進(jìn)程的編號(hào)
? ? ? multiprocessing.current_process().pid
? ? ? os.getpid()
? 獲取父進(jìn)程的編號(hào)
? ? ? os.getppid()
? 根據(jù)進(jìn)程編號(hào)殺死對(duì)應(yīng)的進(jìn)程
? ? ? os.kill(os.getpid(), 9)
import multiprocessing
import time
import os
def work():
? ? # 查看當(dāng)前進(jìn)程
? ? current_process = multiprocessing.current_process()
? ? print("work:", current_process)
? ? # 獲取當(dāng)前進(jìn)程的編號(hào)
? ? print("work進(jìn)程編號(hào):", current_process.pid, os.getpid())
? ? # 獲取父進(jìn)程的編號(hào)
? ? print("work父進(jìn)程的編號(hào):", os.getppid())
? ? for i in range(10):
? ? ? ? print("工作中....")
? ? ? ? time.sleep(0.2)
? ? ? ? # 擴(kuò)展: 根據(jù)進(jìn)程編號(hào)殺死對(duì)應(yīng)的進(jìn)程
? ? ? ? os.kill(os.getpid(), 9)
if __name__ == '__main__':
? ? # 查看當(dāng)前進(jìn)程
? ? current_process = multiprocessing.current_process()
? ? print("main:", current_process)
? ? # 獲取當(dāng)前進(jìn)程的編號(hào)
? ? print("main進(jìn)程的編號(hào):", current_process.pid)
? ? # 創(chuàng)建子進(jìn)程
? ? sub_process = multiprocessing.Process(target=work)
? ? # 啟動(dòng)進(jìn)程
? ? sub_process.start()
? ? # 主進(jìn)程執(zhí)行打印信息操作
? ? for i in range(20):
? ? ? ? print("我在主進(jìn)程中執(zhí)行...")
? ? ? ? time.sleep(0.2)
<5>給子進(jìn)程指定的函數(shù)傳遞參數(shù)
import multiprocessing
# 顯示人員信息
def show_info(name, age):
? ? print(name, age)
if __name__ == '__main__':
? ? # 創(chuàng)建子進(jìn)程
? ? # 1. group:進(jìn)程組,目前必須使用None,一般不用設(shè)置
? ? # 2. target:執(zhí)行目標(biāo)函數(shù)
? ? # 3. name: 進(jìn)程名稱(chēng)
? ? # 4. args: 以元組方式給函數(shù)傳參
? ? # 5. kwargs: 以字典方式給函數(shù)傳參
? ? sub_process = multiprocessing.Process(target=show_info, name="myprocess", args=("古力娜扎", 18))
? ? # 啟動(dòng)進(jìn)程
? ? sub_process.start()
? ? # sub_process = multiprocessing.Process(target=show_info, name="myprocess", kwargs={"name": "貂蟬", "age": 20})
? ? #
? ? # # 啟動(dòng)進(jìn)程
? ? # sub_process.start()
3.進(jìn)程注意點(diǎn)
<1>進(jìn)程之間不共享全局變量
import multiprocessing
import time
# 定義全局變量
my_list = list()
# 寫(xiě)入數(shù)據(jù)
def write_data():
? ? for i in range(5):
? ? ? ? my_list.append(i)
? ? ? ? time.sleep(0.2)
? ? print("write_data:", my_list)
# 讀取數(shù)據(jù)
def read_data():
? ? print(my_list)
if __name__ == '__main__':
? ? # 創(chuàng)建寫(xiě)入數(shù)據(jù)的進(jìn)程
? ? write_process = multiprocessing.Process(target=write_data)
? ? read_process = multiprocessing.Process(target=read_data)
? ? write_process.start()
? ? # 主進(jìn)程等待寫(xiě)入進(jìn)程執(zhí)行完成以后代碼 再繼續(xù)往下執(zhí)行
? ? write_process.join()
? ? read_process.start()
執(zhí)行結(jié)果:
write_data: [0, 1, 2, 3, 4]
read_data: []
注意:
創(chuàng)建子進(jìn)程其實(shí)是對(duì)主進(jìn)程(除了main方法程序入口以外的,Windows如果創(chuàng)建子進(jìn)程不用main程序入口會(huì)無(wú)限循環(huán)創(chuàng)建進(jìn)程導(dǎo)致程序報(bào)錯(cuò))所有資源進(jìn)行拷貝,進(jìn)程之間相互獨(dú)立,訪問(wèn)的全局變量不是同一個(gè),所以進(jìn)程之間不共享全局變量
多進(jìn)程之間可能出現(xiàn)相同名字的全局變量,但是不是同一個(gè)全局變量,是不同的全局變量,只不過(guò)名字相同而已
<2>主進(jìn)程會(huì)等待所有的子進(jìn)程執(zhí)行完成程序再退出
import multiprocessing
import time
# 測(cè)試子進(jìn)程是否執(zhí)行完成以后主進(jìn)程才能退出
def work():
? ? for i in range(10):
? ? ? ? print("工作中...")
? ? ? ? time.sleep(0.2)
if __name__ == '__main__':
? ? # 創(chuàng)建子進(jìn)程
? ? work_process = multiprocessing.Process(target=work)
? ? work_process.start()
? ? # 讓主進(jìn)程等待1秒鐘
? ? time.sleep(1)
? ? print("主進(jìn)程執(zhí)行完成了啦")
總結(jié): 主進(jìn)程會(huì)等待所有的子進(jìn)程執(zhí)行完成以后程序再退出
<3>銷(xiāo)毀子進(jìn)程的代碼
設(shè)置守護(hù)主進(jìn)程,主進(jìn)程退出后子進(jìn)程直接銷(xiāo)毀,不再執(zhí)行子進(jìn)程中的代碼
子進(jìn)程名.daemon = True
讓子進(jìn)程直接銷(xiāo)毀,表示終止執(zhí)行, 主進(jìn)程退出之前,把所有的子進(jìn)程直接銷(xiāo)毀就可以了
子進(jìn)程名.terminate()
import multiprocessing
import time
# 測(cè)試子進(jìn)程是否執(zhí)行完成以后主進(jìn)程才能退出
def work():
? ? for i in range(10):
? ? ? ? print("工作中...")
? ? ? ? time.sleep(0.2)
if __name__ == '__main__':
? ? # 創(chuàng)建子進(jìn)程
? ? work_process = multiprocessing.Process(target=work)
? ? # 設(shè)置守護(hù)主進(jìn)程,主進(jìn)程退出后子進(jìn)程直接銷(xiāo)毀,不再執(zhí)行子進(jìn)程中的代碼
? ? # work_process.daemon = True
? ? work_process.start()
? ? # 讓主進(jìn)程等待1秒鐘
? ? time.sleep(1)
? ? print("主進(jìn)程執(zhí)行完成了啦")
? ? # 讓子進(jìn)程直接銷(xiāo)毀,表示終止執(zhí)行, 主進(jìn)程退出之前,把所有的子進(jìn)程直接銷(xiāo)毀就可以了
? ? work_process.terminate()
? ? # 總結(jié): 主進(jìn)程會(huì)等待所有的子進(jìn)程執(zhí)行完成以后程序再退出
小結(jié):
? 進(jìn)程之間不共享全局變量
? 主進(jìn)程會(huì)等待所有的子進(jìn)程執(zhí)行完成程序再退出
4.進(jìn)程間通信-Queue
<1>Queue的使用
可以使用multiprocessing模塊的Queue實(shí)現(xiàn)多進(jìn)程之間的數(shù)據(jù)傳遞,Queue本身是一個(gè)消息隊(duì)列程序
首先用一個(gè)小實(shí)例來(lái)演示一下Queue的工作原理:
import multiprocessing
import time
if __name__ == '__main__':
? ? # 創(chuàng)建消息隊(duì)列, 3:表示隊(duì)列中最大消息個(gè)數(shù)
? ? queue = multiprocessing.Queue(3)
? ? # 放入數(shù)據(jù)
? ? queue.put(1)
? ? queue.put("hello")
? ? queue.put([3,5])
? ? # 總結(jié): 隊(duì)列可以放入任意數(shù)據(jù)類(lèi)型
? ? # 提示: 如果隊(duì)列滿了,需要等待隊(duì)列有空閑位置才能放入數(shù)據(jù),否則一直等待
? ? # queue.put((5,6))
? ? # 提示: 如果隊(duì)列滿了,不等待隊(duì)列有空閑位置,如果放入不成功直接崩潰
? ? # queue.put_nowait((5,6))
? ? # 建議: 向隊(duì)列放入數(shù)據(jù)統(tǒng)一使用put
? ? # 查看隊(duì)列是否滿了
? ? # print(queue.full())
? ? # 注意點(diǎn):queue.empty()判斷隊(duì)列是否空了不可靠
? ? # 查看隊(duì)列是否空了
? ? # print(queue.empty())
? ? # 解決辦法: 1. 加延時(shí)操作 2. 使用判斷隊(duì)列的個(gè)數(shù),不使用empty
? ? # time.sleep(0.01)
? ? if queue.qsize() == 0:
? ? ? ? print("隊(duì)列為空")
? ? else:
? ? ? ? print("隊(duì)列不為空")
? ? # 獲取隊(duì)列的個(gè)數(shù)
? ? size = queue.qsize()
? ? print(size)
? ? # 獲取數(shù)據(jù)
? ? value = queue.get()
? ? print(value)
? ? # 獲取隊(duì)列的個(gè)數(shù)
? ? size = queue.qsize()
? ? print(size)
? ? # 獲取數(shù)據(jù)
? ? value = queue.get()
? ? print(value)
? ? # 獲取數(shù)據(jù)
? ? value = queue.get()
? ? print(value)
? ? # 獲取隊(duì)列的個(gè)數(shù)
? ? size = queue.qsize()
? ? print(size)
? ? # 提示:如果隊(duì)列空了,再取值需要等待,只有隊(duì)列有值以后才能獲取隊(duì)列中數(shù)據(jù)
? ? # value = queue.get()
? ? # print(value)
? ? # queue.get_nowait()提示: 如果隊(duì)列空了 ,不需要等待隊(duì)列有值,但是如果取值的時(shí)候發(fā)現(xiàn)隊(duì)列空了直接崩潰
? ? # 建議大家: 向隊(duì)列取值使用get
? ? # value = queue.get_nowait()
? ? # print(value)
說(shuō)明:
初始化Queue()對(duì)象時(shí)(例如:q=Queue()),若括號(hào)中沒(méi)有指定最大可接收的消息數(shù)量,或數(shù)量為負(fù)值,那么就代表可接受的消息數(shù)量沒(méi)有上限(直到內(nèi)存的盡頭);
? Queue.qsize():返回當(dāng)前隊(duì)列包含的消息數(shù)量;
? Queue.empty():如果隊(duì)列為空,返回True,反之False , 注意這個(gè)操作是不可靠的。
? Queue.full():如果隊(duì)列滿了,返回True,反之False;
? Queue.get([block[, timeout]]):獲取隊(duì)列中的一條消息,然后將其從列隊(duì)中移除,block默認(rèn)值為T(mén)rue;
1)如果block(阻塞)使用默認(rèn)值,且沒(méi)有設(shè)置timeout(暫時(shí)休息)(單位秒),消息列隊(duì)如果為空,此時(shí)程序?qū)⒈蛔枞ㄍT谧x取狀態(tài)),直到從消息列隊(duì)讀到消息為止,如果設(shè)置了timeout,則會(huì)等待timeout秒,若還沒(méi)讀取到任何消息,則拋出"Queue.Empty"異常;
2)如果block值為False,消息列隊(duì)如果為空,則會(huì)立刻拋出"Queue.Empty"異常;
? Queue.get_nowait():相當(dāng)Queue.get(False);
? Queue.put(item,[block[, timeout]]):將item消息寫(xiě)入隊(duì)列,block默認(rèn)值為T(mén)rue;
1)如果block使用默認(rèn)值,且沒(méi)有設(shè)置timeout(單位秒),消息列隊(duì)如果已經(jīng)沒(méi)有空間可寫(xiě)入,此時(shí)程序?qū)⒈蛔枞ㄍT趯?xiě)入狀態(tài)),直到從消息列隊(duì)騰出空間為止,如果設(shè)置了timeout,則會(huì)等待timeout秒,若還沒(méi)空間,則拋出"Queue.Full"異常;
2)如果block值為False,消息列隊(duì)如果沒(méi)有空間可寫(xiě)入,則會(huì)立刻拋出"Queue.Full"異常;
? Queue.put_nowait(item):相當(dāng)Queue.put(item, False);
<2>消息隊(duì)列Queue完成進(jìn)程間通信的演練
我們以Queue為例,在父進(jìn)程中創(chuàng)建兩個(gè)子進(jìn)程,一個(gè)往Queue里寫(xiě)數(shù)據(jù),一個(gè)從Queue里讀數(shù)據(jù):
import multiprocessing
import time
# 寫(xiě)入數(shù)據(jù)
def write_data(queue):
? ? for i in range(10):
? ? ? ? if queue.full():
? ? ? ? ? ? print("隊(duì)列滿了")
? ? ? ? ? ? break
? ? ? ? queue.put(i)
? ? ? ? time.sleep(0.2)
? ? ? ? print(i)
# 讀取數(shù)據(jù)
def read_data(queue):
? ? while True:
? ? ? ? # 加入數(shù)據(jù)從隊(duì)列取完了,那么跳出循環(huán)
? ? ? ? if queue.qsize() == 0:
? ? ? ? ? ? print("隊(duì)列空了")
? ? ? ? ? ? break
? ? ? ? value = queue.get()
? ? ? ? print(value)
if __name__ == '__main__':
? ? # 創(chuàng)建消息隊(duì)列
? ? queue = multiprocessing.Queue(5)
? ? # 創(chuàng)建寫(xiě)入數(shù)據(jù)的進(jìn)程
? ? write_process = multiprocessing.Process(target=write_data, args=(queue,))
? ? # 創(chuàng)建讀取數(shù)據(jù)的進(jìn)程
? ? read_process = multiprocessing.Process(target=read_data, args=(queue,))
? ? # 啟動(dòng)進(jìn)程
? ? write_process.start()
? ? # 主進(jìn)程等待寫(xiě)入進(jìn)程執(zhí)行完成以后代碼再繼續(xù)往下執(zhí)行
? ? write_process.join()
? ? read_process.start()
小結(jié):
? 從隊(duì)列取值使用get方法,向隊(duì)列放入值使用put方法
? 消息隊(duì)列判斷隊(duì)列是否為空不可靠,可以使用延時(shí)和根據(jù)個(gè)數(shù)進(jìn)行判斷
5.進(jìn)程池Pool
進(jìn)程池的好處:
? 根據(jù)任務(wù)自動(dòng)創(chuàng)建進(jìn)程
? 合理利用指定進(jìn)程完成多任務(wù)
<1>進(jìn)程池的概念
池子里面放的是進(jìn)程,進(jìn)程池會(huì)根據(jù)任務(wù)執(zhí)行情況自動(dòng)創(chuàng)建進(jìn)程,而且盡量少創(chuàng)建進(jìn)程,合理利用進(jìn)程池中的進(jìn)程完成多任務(wù)
(根據(jù)任務(wù)執(zhí)行情況自動(dòng)創(chuàng)建進(jìn)程,并不是一開(kāi)始就創(chuàng)建最大數(shù)量的進(jìn)程)
當(dāng)需要?jiǎng)?chuàng)建的子進(jìn)程數(shù)量不多時(shí),可以直接利用multiprocessing中的Process動(dòng)態(tài)成生多個(gè)進(jìn)程,但如果是上百甚至上千個(gè)目標(biāo),手動(dòng)的去創(chuàng)建進(jìn)程的工作量巨大,此時(shí)就可以用到multiprocessing模塊提供的Pool方法。
初始化Pool時(shí),可以指定一個(gè)最大進(jìn)程數(shù),當(dāng)有新的請(qǐng)求提交到Pool中時(shí),如果池還沒(méi)有滿,那么就會(huì)創(chuàng)建一個(gè)新的進(jìn)程用來(lái)執(zhí)行該請(qǐng)求;但如果池中的進(jìn)程數(shù)已經(jīng)達(dá)到指定的最大值,那么該請(qǐng)求就會(huì)等待,直到池中有進(jìn)程結(jié)束,才會(huì)用之前的進(jìn)程來(lái)執(zhí)行新的任務(wù).
<2>進(jìn)程池同步執(zhí)行任務(wù)
進(jìn)程池同步執(zhí)行任務(wù)表示進(jìn)程池中的進(jìn)程在執(zhí)行任務(wù)的時(shí)候一個(gè)執(zhí)行完成另外一個(gè)才能執(zhí)行,如果沒(méi)有執(zhí)行完會(huì)等待上一個(gè)進(jìn)程執(zhí)行
進(jìn)程池同步實(shí)例代碼
import multiprocessing
import time
# 拷貝任務(wù)
def work():
? ? print("復(fù)制中...", multiprocessing.current_process().pid)
? ? time.sleep(0.5)
if __name__ == '__main__':
? ? # 創(chuàng)建進(jìn)程池
? ? # 3:進(jìn)程池中進(jìn)程的最大個(gè)數(shù),如果不設(shè)置,默認(rèn)最大進(jìn)程個(gè)數(shù)為電腦CPU的核數(shù)
? ? pool = multiprocessing.Pool(3)
? ? # 模擬大批量的任務(wù),讓進(jìn)程池去執(zhí)行
? ? for i in range(5):
? ? ? ? # 循環(huán)讓進(jìn)程池執(zhí)行對(duì)應(yīng)的work任務(wù)
? ? ? ? # 同步執(zhí)行任務(wù),一個(gè)任務(wù)執(zhí)行完成以后另外一個(gè)任務(wù)才能執(zhí)行
? ? ? ? pool.apply(work)
<3>進(jìn)程池異步執(zhí)行任務(wù)
進(jìn)程池異步執(zhí)行任務(wù)表示進(jìn)程池中的進(jìn)程同時(shí)執(zhí)行任務(wù),進(jìn)程之間不會(huì)等待
異步執(zhí)行,任務(wù)執(zhí)行不會(huì)等待,多個(gè)任務(wù)一起執(zhí)行
進(jìn)程池名.apply_async(任務(wù)名)
? ? # 關(guān)閉進(jìn)程池,意思告訴主進(jìn)程以后不會(huì)有新的任務(wù)添加進(jìn)來(lái)
? ? 進(jìn)程池名.close()
? ? # 主進(jìn)程等待進(jìn)程池執(zhí)行完成以后程序再退出
? ? 進(jìn)程池名.join()
進(jìn)程池異步實(shí)例代碼
# 進(jìn)程池:池子里面放的進(jìn)程,進(jìn)程池會(huì)根據(jù)任務(wù)執(zhí)行情況自動(dòng)創(chuàng)建進(jìn)程,而且盡量少創(chuàng)建進(jìn)程,合理利用進(jìn)程池中的進(jìn)程完成多任務(wù)
import multiprocessing
import time
# 拷貝任務(wù)
def work():
? ? print("復(fù)制中...", multiprocessing.current_process().pid)
? ? # 獲取當(dāng)前進(jìn)程的守護(hù)狀態(tài)
? ? # 提示:使用進(jìn)程池創(chuàng)建的進(jìn)程是守護(hù)主進(jìn)程的狀態(tài)true,默認(rèn)自己通過(guò)Process創(chuàng)建的進(jìn)程不是守護(hù)主進(jìn)程的狀態(tài)false
? ? # print(multiprocessing.current_process().daemon)
? ? time.sleep(0.5)
if __name__ == '__main__':
? ? # 創(chuàng)建進(jìn)程池
? ? # 3:進(jìn)程池中進(jìn)程的最大個(gè)數(shù)
? ? pool = multiprocessing.Pool(3)
? ? # 模擬大批量的任務(wù),讓進(jìn)程池去執(zhí)行
? ? for i in range(5):
? ? ? ? # 循環(huán)讓進(jìn)程池執(zhí)行對(duì)應(yīng)的work任務(wù)
? ? ? ? # 同步執(zhí)行任務(wù),一個(gè)任務(wù)執(zhí)行完成以后另外一個(gè)任務(wù)才能執(zhí)行
? ? ? ? # pool.apply(work)
? ? ? ? # 異步執(zhí)行,任務(wù)執(zhí)行不會(huì)等待,多個(gè)任務(wù)一起執(zhí)行
? ? ? ? pool.apply_async(work)
? ? # 關(guān)閉進(jìn)程池,意思告訴主進(jìn)程以后不會(huì)有新的任務(wù)添加進(jìn)來(lái)
? ? pool.close()
? ? # 主進(jìn)程等待進(jìn)程池執(zhí)行完成以后程序再退出
? ? pool.join()
小結(jié):
multiprocessing.Pool常用函數(shù)解析:
? 同步執(zhí)行:apply(func[, args[, kwds]]): 阻塞方式調(diào)用函數(shù),args表示以元組方式給函數(shù)傳參,kwds表示以字典方式給函數(shù)傳參
? 異步執(zhí)行:apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用函數(shù),args表示以元組方式給函數(shù)傳參,kwds表示以字典方式給函數(shù)傳參
? close():關(guān)閉Pool,使其不再接受新的任務(wù);
? terminate():不管任務(wù)是否完成,立即終止;
? join():主進(jìn)程阻塞,等待子進(jìn)程的退出, 必須在close或terminate之后使用;
6.進(jìn)程、線程對(duì)比
<1>功能對(duì)比
? 進(jìn)程,能夠完成多任務(wù),比如 在一臺(tái)電腦上能夠同時(shí)運(yùn)行多個(gè)QQ
? 線程,能夠完成多任務(wù),比如 一個(gè)QQ中的多個(gè)聊天窗口
<2>定義對(duì)比
? 進(jìn)程是系統(tǒng)進(jìn)行資源分配基本單位,每啟動(dòng)一個(gè)進(jìn)程操作系統(tǒng)都需要為其分配運(yùn)行資源。
? 線程是CPU調(diào)度基本單位,是運(yùn)行程序中的一個(gè)執(zhí)行分支。
? 總結(jié):進(jìn)程是操作系統(tǒng)資源分配的基本單位,線程是CPU調(diào)度的基本單位
<3>關(guān)系對(duì)比
? 線程是依附在進(jìn)程里面的,沒(méi)有進(jìn)程就沒(méi)有線程
? 一個(gè)進(jìn)程默認(rèn)提供一條線程,進(jìn)程可以創(chuàng)建多個(gè)線程
<4>區(qū)別
? 進(jìn)程之間不共享全局變量
? 線程之間共享全局變量,但是要注意資源競(jìng)爭(zhēng)的問(wèn)題,解決辦法: 互斥鎖或者線程同步
? 創(chuàng)建進(jìn)程的資源開(kāi)銷(xiāo)要比創(chuàng)建線程的資源開(kāi)銷(xiāo)要大
? 進(jìn)程是操作系統(tǒng)資源分配的基本單位,線程是CPU調(diào)度的基本單位
? 線程不能夠獨(dú)立執(zhí)行,必須依存在進(jìn)程中
? 多進(jìn)程開(kāi)發(fā)比單進(jìn)程多線程開(kāi)發(fā)穩(wěn)定性要強(qiáng)
<5>優(yōu)缺點(diǎn)
多進(jìn)程:
? 優(yōu)點(diǎn):可以用多核
? 缺點(diǎn):資源開(kāi)銷(xiāo)大
多線程:
? 優(yōu)點(diǎn):資源開(kāi)銷(xiāo)小
? 缺點(diǎn):不能使用多核
7.文件夾拷貝器-多任務(wù)
<1>功能要求
? 使用進(jìn)程池完成多任務(wù)文件夾的拷貝
import os
import shutil
import multiprocessing
# import time
# 文件拷貝任務(wù)
def copy_work(src_dir, dst_dir, file_name):
? ? # 查看進(jìn)程對(duì)象
? ? pid = multiprocessing.current_process().pid
? ? print(pid)
? ? # 拼接源文件的路徑
? ? src_file_path = src_dir + "/" + file_name
? ? # 拼接目標(biāo)文件的路徑
? ? dst_file_path = dst_dir + "/" + file_name
? ? with open(dst_file_path, "wb") as dst_file:
? ? ? ? # 打源文件讀取文件中的數(shù)據(jù)
? ? ? ? with open(src_file_path, "rb") as src_file:
? ? ? ? ? ? while True:
? ? ? ? ? ? ? ? # 讀取數(shù)據(jù)
? ? ? ? ? ? ? ? src_file_data = src_file.read(1024)
? ? ? ? ? ? ? ? if src_file_data:
? ? ? ? ? ? ? ? ? ? # 寫(xiě)入到目標(biāo)文件里面
? ? ? ? ? ? ? ? ? ? dst_file.write(src_file_data)
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? break
? ? # time.sleep(0.5)
if __name__ == '__main__':
? ? # 源目錄
? ? src_dir = "test"
? ? # 目標(biāo)目錄
? ? dst_dir = "/home/python/Desktop/test"
? ? # 判斷文件夾是否存在
? ? if os.path.exists(dst_dir):
? ? ? ? # 存在則刪除文件夾及文件夾里面的所有文件
? ? ? ? shutil.rmtree(dst_dir)
? ? # 創(chuàng)建目標(biāo)文件夾
? ? os.mkdir(dst_dir)
? ? # 獲取源目錄里面文件的列表
? ? file_name_list = os.listdir(src_dir)
? ? # 創(chuàng)建進(jìn)程池
? ? pool = multiprocessing.Pool(3)
? ? # 遍歷文件里面獲取文件名
? ? for file_name in file_name_list:
? ? ? ? # 使用進(jìn)程池執(zhí)行拷貝任務(wù),使用*args和**kwagrs傳參數(shù)!此處選擇元組
? ? ? ? pool.apply_async(copy_work, (src_dir, dst_dir, file_name))
? ? # 關(guān)閉進(jìn)程池
? ? pool.close()
? ? # 主進(jìn)程等待進(jìn)程池執(zhí)行完成以后程序再退出
? ? pool.join()
小結(jié):
進(jìn)程池在執(zhí)行任務(wù)的時(shí)候會(huì)盡量少創(chuàng)建進(jìn)程,合理利用現(xiàn)有進(jìn)程完成多任務(wù),這樣可以減少資源開(kāi)銷(xiāo)