python網(wǎng)絡(luò)編程基礎(chǔ)(連載)06 多進(jìn)程

5 多進(jìn)程

gitbook鏈接:用python帶你進(jìn)入AI中的深度學(xué)習(xí)技術(shù)領(lǐng)域https://www.gitbook.com/book/scrappyzhang/python_to_deeplearn/details

github鏈接:https://github.com/ScrappyZhang/python_web_Crawler_DA_ML_DL

5.1 進(jìn)程

程序:例如xxx.py這是程序,是一個(gè)靜態(tài)的

進(jìn)程:一個(gè)程序運(yùn)行起來(lái)后,代碼+用到的資源 稱(chēng)之為進(jìn)程,它是操作系統(tǒng)分配資源的基本單元。

進(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)

5.2 python實(shí)現(xiàn)多進(jìn)程

我們來(lái)試想一下,在一個(gè)演唱會(huì)上,歌手歌唱、舞者翩翩起舞,各司其職才能達(dá)到較好的效果。我們可以這么理解:演唱會(huì)這個(gè)程序中有幾個(gè)進(jìn)程,一個(gè)是歌手歌唱,一個(gè)是舞者翩翩起舞,還有一個(gè)總協(xié)調(diào)的劇本。接下來(lái)我們就用python來(lái)實(shí)現(xiàn)這個(gè)想法:一個(gè)python程序有兩個(gè)子進(jìn)程:歌手歌唱、舞者翩翩起舞。

python中的multiprocessing模塊就是跨平臺(tái)版本的多進(jìn)程模塊,提供了一個(gè)Process類(lèi)來(lái)代表一個(gè)進(jìn)程對(duì)象,這個(gè)對(duì)象可以理解為是一個(gè)獨(dú)立的進(jìn)程,可以執(zhí)行另外的事情。Process的語(yǔ)法結(jié)構(gòu)如下:

Process([group [, target [, name [, args [, kwargs]]]]])

  • target:如果傳遞了函數(shù)的引用,可以任務(wù)這個(gè)子進(jìn)程就執(zhí)行這里的代碼
  • args:給target指定的函數(shù)傳遞的參數(shù),以元組的方式傳遞
  • kwargs:給target指定的函數(shù)傳遞命名參數(shù)
  • name:給進(jìn)程設(shè)定一個(gè)名字,可以不設(shè)定
  • group:指定進(jìn)程組,大多數(shù)情況下用不到

Process創(chuàng)建的實(shí)例對(duì)象的常用方法:

  • start():?jiǎn)?dòng)子進(jìn)程實(shí)例(創(chuàng)建子進(jìn)程)
  • is_alive():判斷進(jìn)程子進(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))

我們來(lái)實(shí)現(xiàn)多進(jìn)程完成唱歌跳舞吧:

'''net04_sing_dance_multiprocess.py'''
import multiprocessing
import time


def sing():
    for i in range(5):
        print('正在唱歌呢 %d' % i)
        time.sleep(1)  # 休息1秒


def dance():
    for i in range(5):
        print('正在跳舞呢 %d' % i)
        time.sleep(1)  # 休息1秒


if __name__ == '__main__':
    p1 = multiprocessing.Process(target=sing)  # 創(chuàng)建唱歌進(jìn)程
    p2 = multiprocessing.Process(target=dance)  # 創(chuàng)建跳舞進(jìn)程
    p1.start()  # 開(kāi)始運(yùn)行進(jìn)程sing
    p2.start()  # 開(kāi)始運(yùn)行進(jìn)程dance

我們通過(guò)Process分別創(chuàng)建了唱歌子進(jìn)程p1和跳舞子進(jìn)程p2,然后啟動(dòng)使用start()了子進(jìn)程 。從結(jié)果中可以看到唱歌和跳舞完全互不影響,各自進(jìn)行直到結(jié)束。

process1.png

當(dāng)然有經(jīng)驗(yàn)的讀者會(huì)說(shuō),這和多線程、協(xié)程(后續(xù)兩章)效果不一樣么,答曰:不一樣。python的os模塊中有關(guān)getpid方法可以獲取程序的進(jìn)程號(hào),我們通過(guò)在程序中添加os.getpid()來(lái)查看我們的程序有哪些進(jìn)程。在剛開(kāi)始運(yùn)行程序時(shí),我們可以在終端(MAC)輸入ps aux|grep net04查看我們的程序在運(yùn)行時(shí)的進(jìn)程號(hào),然后進(jìn)行對(duì)比確認(rèn)。完整的代碼如下:

'''net04_getpid.py'''
import multiprocessing
import os
import time


def sing():
    print('唱歌進(jìn)程pid: %d' % os.getpid())
    for i in range(5):
        print('正在唱歌呢 %d' % i)
        time.sleep(1)  # 休息1秒


def dance():
    print('跳舞進(jìn)程pid: %d' % os.getpid())
    for i in range(5):
        print('正在跳舞呢 %d' % i)
        time.sleep(1)  # 休息1秒


if __name__ == '__main__':
    print('父進(jìn)程pid: %d' % os.getpid())
    p1 = multiprocessing.Process(target=sing)  # 創(chuàng)建唱歌進(jìn)程
    p2 = multiprocessing.Process(target=dance)  # 創(chuàng)建跳舞進(jìn)程
    p1.start()  # 開(kāi)始運(yùn)行進(jìn)程sing
    p2.start()  # 開(kāi)始運(yùn)行進(jìn)程dance

從結(jié)果中可以看到,我們的程序運(yùn)行時(shí)共占用了三個(gè)進(jìn)程:19277、19278、19279,和我們預(yù)想的一樣。由于進(jìn)程時(shí)系統(tǒng)分配資源的基本單元,所以我們的三個(gè)進(jìn)程程序相比單進(jìn)程程序會(huì)占用系統(tǒng)更多的資源去同步完成唱歌和跳舞的任務(wù)。

process2.png

既然我們實(shí)現(xiàn)了多進(jìn)程完成唱歌跳舞,那我們更進(jìn)一步的實(shí)現(xiàn)告訴子進(jìn)程讓誰(shuí)唱歌讓誰(shuí)跳舞吧,沒(méi)錯(cuò),我們就是導(dǎo)演,我們說(shuō)了算。通過(guò)在Process對(duì)象創(chuàng)建時(shí)通過(guò)對(duì)args或者kwargs進(jìn)行賦值來(lái)傳遞參數(shù)就可以實(shí)現(xiàn)。

singer = 'Jam'
sing_name = '不露聲色'
p1 = multiprocessing.Process(target=sing, args=(singer, sing_name))  # 創(chuàng)建唱歌進(jìn)程,告訴子進(jìn)程是Jam唱不露聲色
p2 = multiprocessing.Process(target=dance,kwargs={'dancer':'杰克遜'})  # 創(chuàng)建跳舞進(jìn)程,告訴子進(jìn)程是杰克遜來(lái)唱歌啦

實(shí)例完整代碼如下:

'''net04_sing_dance_variable.py'''
import multiprocessing
import time


def sing(name, sing_name):
    for i in range(5):
        print(name, '正在唱歌%s呢 %d' % (sing_name, i))
        time.sleep(1)  # 休息1秒


def dance(**kwargs):
    dancer = kwargs['dancer']
    for i in range(5):
        print('%s正在伴舞呢 %d' % (dancer,i))
        time.sleep(1)  # 休息1秒


if __name__ == '__main__':
    singer = 'Jam'
    sing_name = '不露聲色'
    p1 = multiprocessing.Process(target=sing, args=(singer, sing_name))  # 創(chuàng)建唱歌進(jìn)程,告訴子進(jìn)程是Jam唱不露聲色
    p2 = multiprocessing.Process(target=dance,kwargs={'dancer':'杰克遜'})  # 創(chuàng)建跳舞進(jìn)程,告訴子進(jìn)程是杰克遜來(lái)唱歌啦
    p1.start()  # 開(kāi)始運(yùn)行進(jìn)程sing
    p2.start()  # 開(kāi)始運(yùn)行進(jìn)程dance

從運(yùn)行結(jié)果中我們可以很清晰的看到Jam唱不露聲色的時(shí)候杰克遜在為她伴舞——so crazy。

process3.png

5.3 進(jìn)程間不共享全局變量

上一章我們知道線程間會(huì)共享全局變量,本節(jié)我們來(lái)想一下,進(jìn)程間呢?當(dāng)然不會(huì)啦,假如我們的電腦上裝有QQ音樂(lè)和網(wǎng)易云音樂(lè),在網(wǎng)易云音樂(lè)收藏的歌單不會(huì)自動(dòng)到QQ音樂(lè)的。我們一起看個(gè)實(shí)例吧。定義一個(gè)全局變量global_num=0,然后在唱歌和跳舞兩個(gè)代碼塊中添加global_num+1操作。我們會(huì)發(fā)現(xiàn),父進(jìn)程、sing子進(jìn)程和dance子進(jìn)程之間global_num并無(wú)半點(diǎn)關(guān)系,即進(jìn)程間不共享全局變量。

'''net04_global_variables.py'''
import multiprocessing
import time

global_num = 0


def sing():
    global global_num
    print('開(kāi)始:全局變量sing global_num= ', global_num)
    for i in range(5):
        print('正在唱歌呢 %d' % i)
        global_num = global_num + 1  # 修改全局變量
        time.sleep(1)  # 休息1秒
    print('結(jié)束:全局變量sing global_num= ', global_num)


def dance():
    global global_num
    print('開(kāi)始:全局變量dance global_num= ', global_num)
    for i in range(5):
        print('正在跳舞呢 %d' % i)
        global_num = global_num + 1  # 修改全局變量
        time.sleep(1)  # 休息1秒
    print('結(jié)束:全局變量dance global_num= ', global_num)


if __name__ == '__main__':
    print('開(kāi)始:全局變量main global_num= ', global_num)
    p1 = multiprocessing.Process(target=sing)  # 創(chuàng)建唱歌進(jìn)程
    p2 = multiprocessing.Process(target=dance)  # 創(chuàng)建跳舞進(jìn)程
    p1.start()
    p2.start()
    p1.join()  # 待子進(jìn)程p1執(zhí)行完畢后再執(zhí)行下面的語(yǔ)句
    p2.join()  # 待子進(jìn)程p2執(zhí)行完畢后再執(zhí)行下面的語(yǔ)句
    print('結(jié)束:全局變量main global_num= ', global_num)
process4.png

5.4 進(jìn)程間通信

上一節(jié)我們了解到進(jìn)程間不共享全局變量,但是試想一下,我們電腦上登錄了兩個(gè)QQ并需要互傳消息或者杰克遜作為伴舞者打算給Jam遞花,怎么辦呢?這就要涉及進(jìn)程間通信。在多進(jìn)程程序中,有眾多的進(jìn)程間通信方式,我們今天通過(guò)python中multiprocessing模塊中的Queue來(lái)實(shí)現(xiàn)進(jìn)程間的通信。它的基本語(yǔ)法如下:

初始化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 ;
  • 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(單位秒),消息列隊(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)。

我們來(lái)看一下下面這個(gè)例子:

'''net04_queue_sample.py'''
from multiprocessing import Queue

q = Queue(3)  # 初始化一個(gè)Queue對(duì)象,最多可接收三條put消息
q.put("消息1")
q.put("消息2")
print(q.full())  # False
q.put("消息3")
print(q.full())  # True

# 因?yàn)橄⒘嘘?duì)已滿,所以下面的try都會(huì)拋出異常,第一個(gè)try會(huì)等待2秒后再拋出異常,第二個(gè)Try會(huì)立刻拋出異常
try:
    q.put("消息4", True, 2)
except:
    print("消息列隊(duì)已滿,現(xiàn)有消息數(shù)量:%s" % q.qsize()) # mac os不支持qsize
# Note that this may raise NotImplementedError on Unix platforms like Mac OS X where sem_getvalue() is not implemented.

try:
    q.put_nowait("消息4")
except:
    print("消息列隊(duì)已滿,現(xiàn)有消息數(shù)量:%s" % q.qsize())

# 推薦的方式,先判斷消息列隊(duì)是否已滿,再寫(xiě)入
if not q.full():
    q.put_nowait("消息4")

# 讀取消息時(shí),先判斷消息列隊(duì)是否為空,再讀取
if not q.empty():
    for i in range(q.qsize()):
        print(q.get_nowait())

運(yùn)行結(jié)果與語(yǔ)法中定義的一樣,put為寫(xiě)入,get為讀出;full為判斷是否寫(xiě)滿等。

False
True
消息列隊(duì)已滿,現(xiàn)有消息數(shù)量:3
消息列隊(duì)已滿,現(xiàn)有消息數(shù)量:3
消息1
消息2
消息3

接下來(lái)我們就通過(guò)multiprocessing模塊中的Queue來(lái)實(shí)現(xiàn)唱歌跳舞時(shí)杰克遜為Jam遞花這一構(gòu)想。具體代碼如下:

'''net04_sing_dance_queue.py'''
import multiprocessing
import time


def sing(name, sing_name):
    for i in range(5):
        print(name, '正在唱歌%s呢 %d' % (sing_name, i))
        time.sleep(1)  # 休息1秒
    while True:
        if not q.empty():
            value = q.get() # 從隊(duì)列中讀取數(shù)據(jù)
            print('Jam收到了', value)
        else:
            break


def dance(**kwargs):
    dancer = kwargs['dancer']
    q.put('花') # 向隊(duì)列中寫(xiě)入花數(shù)據(jù)
    print('杰克遜向Jam遞了一朵花')
    for i in range(5):
        print('%s正在伴舞呢 %d' % (dancer, i))
        time.sleep(1)  # 休息1秒


if __name__ == '__main__':
    singer = 'Jam'
    sing_name = '不露聲色'
    q = multiprocessing.Queue() # 創(chuàng)建隊(duì)列
    p1 = multiprocessing.Process(target=sing, args=(singer, sing_name))  # 創(chuàng)建唱歌進(jìn)程
    p2 = multiprocessing.Process(target=dance, kwargs={'dancer': '杰克遜'})  # 創(chuàng)建跳舞進(jìn)程
    p1.start()  # 開(kāi)始運(yùn)行進(jìn)程sing
    p2.start()  # 開(kāi)始運(yùn)行進(jìn)程dance

在這個(gè)構(gòu)想的代碼中,我們首先創(chuàng)建了一個(gè)消息隊(duì)列Queue的實(shí)例對(duì)象q,然后在sing代碼塊中添加從隊(duì)列中讀取數(shù)據(jù)的語(yǔ)句q.get()代表收取禮物、在dance代碼塊中添加向隊(duì)列中寫(xiě)入數(shù)據(jù)的語(yǔ)句q.put(‘花’)代表送出了花。這樣便實(shí)現(xiàn)了舞者和歌手兩個(gè)進(jìn)程之間的通信。從代碼執(zhí)行的結(jié)果來(lái)看,確實(shí)如此。

process6.png

5.5 進(jìn)程池Pool

在之前的進(jìn)程創(chuàng)建過(guò)程中我們通過(guò)multiprocessing中的Process來(lái)生成了唱歌和跳舞進(jìn)程,但如果我們這次演唱會(huì)請(qǐng)的是少女時(shí)代組合呢?那可是有好多人呢,一個(gè)一個(gè)創(chuàng)建太累了,有沒(méi)有批量創(chuàng)建的方法呢?答曰:有。我們可以使用進(jìn)程池的概念來(lái)批量創(chuàng)建進(jìn)程,即multiprocessing模塊中的Pool。

multiprocessing.Pool常用的函數(shù)介紹:

  • apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用func(并行執(zhí)行,堵塞方式必須等待上一個(gè)進(jìn)程退出才能執(zhí)行下一個(gè)進(jìn)程),args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)列表;
  • close():關(guān)閉Pool,使其不再接受新的任務(wù);
  • terminate():不管任務(wù)是否完成,立即終止;
  • join():主進(jìn)程阻塞,等待子進(jìn)程的退出, 必須在close或terminate之后使用;

了解了基本語(yǔ)法,我們就來(lái)批量創(chuàng)建幾個(gè)歌手進(jìn)程吧:
首先我們創(chuàng)建一個(gè)最大只有3個(gè)進(jìn)程的進(jìn)程池:

processes = multiprocessing.Pool(3)

其次我們用進(jìn)程池中的apply_async來(lái)創(chuàng)建五個(gè)歌手進(jìn)程。

'''net04_process_pool.py'''
import multiprocessing
import time


def sing(singer_num, sleep_time):
    for i in range(4):
        print('歌手', singer_num, '正在唱歌呢 %d' % i)
        time.sleep(sleep_time)  # 休息


if __name__ == '__main__':
    processes = multiprocessing.Pool(3) # 創(chuàng)建進(jìn)程池,最大進(jìn)程數(shù)為3
    for i in range(5):
        processes.apply_async(sing, (i + 1, 1 + 0.3 * i)) # 進(jìn)程池創(chuàng)建進(jìn)程 ,傳入?yún)?shù)為歌手編號(hào)和歌唱間隔休息時(shí)間

    print('歌唱開(kāi)始')
    processes.close()
    processes.join()
    print('歌唱結(jié)束')

由于我們創(chuàng)建的進(jìn)程池最大只能容納3個(gè)進(jìn)程,所以本實(shí)例中的4號(hào)歌手和5號(hào)歌手進(jìn)程需要等到之前幾位歌手進(jìn)程中的某一個(gè)執(zhí)行完畢方可創(chuàng)建。具體見(jiàn)結(jié)果。

proceing1.png

注意:如果要使用Pool進(jìn)程池創(chuàng)建進(jìn)程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue()。

5.6 進(jìn)程與線程對(duì)比

功能 {#功能}

  • 進(jìn)程,能夠完成多任務(wù),比如 在一臺(tái)電腦上能夠同時(shí)運(yùn)行多個(gè)QQ
  • 線程,能夠完成多任務(wù),比如 一個(gè)QQ中的多個(gè)聊天窗口

定義的不同 {#定義的不同}

  • 進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.

  • 線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.

區(qū)別 {#區(qū)別}

  • 一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.
  • 線程的劃分尺度小于進(jìn)程(資源比進(jìn)程少),使得多線程程序的并發(fā)性高。
  • 進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率
  • 線線程不能夠獨(dú)立執(zhí)行,必須依存在進(jìn)程中

優(yōu)缺點(diǎn) {#優(yōu)缺點(diǎn)}

線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開(kāi)銷(xiāo)小,但不利于資源的管理和保護(hù);而進(jìn)程正相反。

5.7 多進(jìn)程實(shí)現(xiàn)文件拷貝

需求實(shí)現(xiàn):

通過(guò)多進(jìn)程的方式實(shí)現(xiàn)拷貝文件夾下的文件(文件夾嵌套不考慮);在拷貝過(guò)程中顯示拷貝進(jìn)度。

根據(jù)流程圖書(shū)寫(xiě)代碼要點(diǎn)

根據(jù)需求,我們可以將代碼劃分為兩大部分:主程序、拷貝函數(shù)。主程序用來(lái)創(chuàng)建每個(gè)文件拷貝操作的子進(jìn)程來(lái)實(shí)現(xiàn)多進(jìn)程拷貝。通過(guò)os模塊的listdir獲取到要拷貝的文件夾內(nèi)的文件名列表,并以此來(lái)創(chuàng)建相應(yīng)的子進(jìn)程,每個(gè)文件一個(gè)進(jìn)程。最后我們通過(guò)進(jìn)程間通信來(lái)讓每個(gè)子進(jìn)程在完成拷貝任務(wù)后來(lái)告知父進(jìn)程它完成了拷貝,并傳回它所拷貝的文件的文件名。父進(jìn)程通過(guò)獲取子進(jìn)程的消息并計(jì)算已經(jīng)完成的文件拷貝數(shù)來(lái)計(jì)算進(jìn)度并顯示。待100%時(shí)結(jié)束程序。

processing11.png

拷貝函數(shù)

文件拷貝:文件讀寫(xiě)操作

open(filename, 'rb')
f.read()
open(filename, 'wb')
f.write()
.close()

與父進(jìn)程通信

queue.put()

主程序

獲取文件列表

os.listdir(path)

多進(jìn)程創(chuàng)建

multiprocessing.Process(拷貝函數(shù))

獲取進(jìn)度

創(chuàng)建隊(duì)列
    multiprocessing.Queue()
獲取子進(jìn)程通信內(nèi)容
    queue.get()

完整代碼

'''net04_file_copy.py'''
import multiprocessing
import os
import time
import random


def copy_file(file_name, src, dest, queue):
    '''拷貝文件的函數(shù)'''
    src_file = open(src + '/' + file_name, 'rb')
    dest_file = open(dest + '/' + file_name, 'wb')

    while True:
        time.sleep(random.random())
        data = src_file.read(4096)
        if data:
            dest_file.write(data)
        else:
            break
    src_file.close()
    dest_file.close()
    queue.put(file_name)


if __name__ == '__main__':
    src_path = input('請(qǐng)輸入你要拷貝的目錄名:')
    try:
        dest_path = src_path + '-備份'
        os.mkdir(dest_path)
        file_list = os.listdir(src_path)
    except Exception as e:
        print(e)
    else:
        queue = multiprocessing.Queue()

        for file in file_list:
            pro = multiprocessing.Process(
                target=copy_file, args=(file, src_path, dest_path, queue)
            )
            pro.start()

        count = 0
        while True:
            queue.get()
            count += 1
            print('\r當(dāng)前進(jìn)度為%d%%' % (100.0 * count / len(file_list)),end='')
            if count == len(file_list):
                break

5.8 小結(jié)

process12.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,746評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,666評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評(píng)論 6 407
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,960評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,200評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,425評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,674評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容

  • 1.進(jìn)程 1.1多線程的引入 現(xiàn)實(shí)生活中 有很多的場(chǎng)景中的事情是同時(shí)進(jìn)行的,比如開(kāi)車(chē)的時(shí)候手和腳共同來(lái)駕駛汽車(chē),再...
    TENG書(shū)閱讀 508評(píng)論 0 0
  • 1.1.1多任務(wù)的引入 什么叫“多任務(wù)”呢?簡(jiǎn)單地說(shuō),就是操作系統(tǒng)可以同時(shí)運(yùn)行多個(gè)任務(wù)。打個(gè)比方,你一邊在用瀏覽器...
    PythonMaO閱讀 472評(píng)論 0 1
  • @(python)[筆記](méi) 目錄 一、什么是進(jìn)程 1.1 進(jìn)程的概念 進(jìn)程的概念起源于操作系統(tǒng),是操作系統(tǒng)最核心的...
    CaiGuangyin閱讀 1,269評(píng)論 0 9
  • 1.進(jìn)程 1.多任務(wù)的引入 有很多的場(chǎng)景中的事情是同時(shí)進(jìn)行的,比如開(kāi)車(chē)的時(shí)候手和腳共同來(lái)駕駛汽車(chē),再比如唱歌跳舞也...
    一只寫(xiě)程序的猿閱讀 583評(píng)論 0 1
  • 不知道什么時(shí)候(可能是某次更新后,10.11之后出現(xiàn)的),F(xiàn)inder左側(cè)的菜單中部分條目變成了英文,如:Down...
    djyuning閱讀 4,277評(píng)論 0 0