Python多進(jìn)程

參考自:

廖雪峰的Python教程
董偉明的博客

知識點(diǎn):

  • Process
  • Pool
  • 進(jìn)程間通信

進(jìn)程(Process)

對于操作系統(tǒng)來說,一個任務(wù)就是一個進(jìn)程(Process),比如打開一個word就是啟動一個word進(jìn)程。它不止干同一件事情,可以同時進(jìn)行打字、打印等子任務(wù)操作,這些進(jìn)程內(nèi)的子任務(wù)就是線程(Thread)

  • 單核CPU也可以執(zhí)行多任務(wù),操作系統(tǒng)輪流
  • 讓各個任務(wù)交替,Task1執(zhí)行0.01秒,切換到Task2,Task2執(zhí)行0.01秒,再切換到Task3,執(zhí)行0.01秒........這樣反復(fù)執(zhí)行下去
  • 真正的并行執(zhí)行多任務(wù)只能在多核CPU上實(shí)現(xiàn)

多進(jìn)程(Multiprocessing)

Multiprocessing模塊提供了一個Process類來代表一個進(jìn)程對象,下面代碼演示了創(chuàng)建一個子進(jìn)程,并等待其結(jié)束

  • os.getpid() 獲取父進(jìn)程的ID
  • 創(chuàng)建子進(jìn)程時,首先創(chuàng)建Process類的實(shí)例,再傳入一個函數(shù)和它的參數(shù)
  • 用start()來啟動子進(jìn)程
  • jion() 等待子進(jìn)程結(jié)束后再繼續(xù)運(yùn)行下去,用于進(jìn)程之間的同步

# -*- coding:utf-8 -*-
import os
from multiprocessing import Process


def run_process(name):
    print('Run child process %s(%s)' % (name, os.getpid()))


if __name__ == '__main__':
    print('Run parent process %s' % os.getpid())
    # 創(chuàng)建子進(jìn)程(創(chuàng)建Process類的實(shí)例p),傳入一個函數(shù)和函數(shù)的參數(shù)
    p = Process(target=run_process, args=('test', ))
    print('Child process will start!')
    # 啟動子進(jìn)程
    p.start()
    # 等待子進(jìn)程結(jié)束后再運(yùn)行下去,用于進(jìn)程間的同步
    p.join()
    print('Child process end!')

執(zhí)行結(jié)果如下:


Run parent process 9156
Child process will start!
Run child process test(1564)
Child process end!

Process finished with exit code 0


Pool

如果要啟動大量的子進(jìn)程,可以使用進(jìn)程池(Pool)。


# -*- coding:utf-8 -*-
import os
import time
import random
from multiprocessing import Pool


def long_time_task(name):
    print('Run task %s()%s' % (name, os.getpid()))
    start = time.time()
    # random.random():隨機(jī)生成0~1之間的浮點(diǎn)數(shù)
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s run %0.2f seconds' % (name, end - start))


if __name__ == '__main__':
    print('Parent process %s' % os.getpid())
    # 創(chuàng)建進(jìn)程池,大小是4,創(chuàng)建Pool類的實(shí)例p,不寫子進(jìn)程數(shù)量,默認(rèn)開到CPU最大
    p = Pool(4)
    # 創(chuàng)建5個子進(jìn)程,apply_async傳入一個函數(shù)和它的參數(shù)
    for i in range(5):
        p.apply_async(long_time_task, args=(i, ))
    print('Waiting all subprocess done!')
    # join()之前必須先調(diào)用close(),調(diào)用close()后就不能再添加新的subprocess了
    p.close()
    # 等待所有子進(jìn)程執(zhí)行完畢
    p.join()
    print('All subprocess done!')

執(zhí)行結(jié)果如下:


Parent process 13524
Waiting all subprocess done!
Run task 0()14440
Run task 1()15016
Run task 2()8072
Run task 3()3268
Task 0 run 0.28 seconds
Run task 4()14440
Task 3 run 1.14 seconds
Task 2 run 1.54 seconds
Task 1 run 2.11 seconds
Task 4 run 2.82 seconds
All subprocess done!

Pool對象需要調(diào)用join()方法會等待所有subprocess執(zhí)行完畢,調(diào)用join()方法之前必須要先調(diào)用close()方法,調(diào)用close()方法后就不能再添加新的subprocess了

我們看到輸出是task0, 1, 2, 3執(zhí)行了,而task4需要等待某個task執(zhí)行完畢才能運(yùn)行,這是因?yàn)槲覀冊O(shè)置了進(jìn)程池大小為4,它只能同時執(zhí)行4個子進(jìn)程,如果不設(shè)置進(jìn)程池大小,就是默認(rèn)電腦的CPU最大核數(shù)

之前用Multiprocess寫過多進(jìn)程爬蟲,抓取速度極快,數(shù)據(jù)量小的甚至可以做到秒抓


進(jìn)程間通信

Process之間都需要通信,Multiprocessing提供了Queue(隊(duì)列)Pipe(管道)來進(jìn)行數(shù)據(jù)的交換

這里是Queue(隊(duì)列)為例子,創(chuàng)建兩個子進(jìn)程,一個寫數(shù)據(jù),一個讀數(shù)據(jù)。創(chuàng)建Queue的實(shí)例q,父進(jìn)程創(chuàng)建隊(duì)列,分別傳遞給write和read兩個子進(jìn)程


# -*- coding:utf-8 -*-
import os
import time
import random
from multiprocessing import Process, Queue


def write(q):
    print('Process write to: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        # 調(diào)用put將value放置隊(duì)列當(dāng)中
        q.put(value)
        time.sleep(random.random())


def read(q):
    print('Proecss to read: %s' % os.getpid())
    while True:
        # 將數(shù)據(jù)從隊(duì)列中取出
        value = q.get(True)
        print('Get %s from queue' % value)


if __name__ == '__main__':
    # 父進(jìn)程創(chuàng)建隊(duì)列,并傳遞給各個子進(jìn)程
    q = Queue()
    # 創(chuàng)建write子進(jìn)程
    pw = Process(target=write, args=(q, ))
    # 創(chuàng)建read子進(jìn)程
    pr = Process(target=read, args=(q, ))
    # 開啟write子進(jìn)程
    pw.start()
    # 開啟read子進(jìn)程
    pr.start()
    # 等待write子進(jìn)程結(jié)束
    pw.join()
    # read子進(jìn)程是死循環(huán),需要強(qiáng)制關(guān)閉
    pr.terminate()

執(zhí)行結(jié)果如下:

Process write to: 868
Put A to queue...
Proecss to read: 9844
Get A from queue
Put B to queue...
Get B from queue
Put C to queue...
Get C from queue

Process finished with exit code 0


董偉明老師寫的多進(jìn)程教程明顯難度要高于廖老師的,用了很多Python的語法糖,需要額外去理解閉包、裝飾器、遞歸,但廖老師的更容易理解

歡迎訪問Treehl的博客
Github

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、進(jìn)程的概念 相信很多同學(xué)都聽說過windows、linux,MacOS都是多任務(wù),多用戶的操作系統(tǒng)。那什么是多...
    轉(zhuǎn)身后的那一回眸閱讀 1,093評論 0 1
  • 想讓python實(shí)現(xiàn)多進(jìn)程(multiprocessing),我們要先區(qū)分不同的操作系統(tǒng)的不同之處。 Linux操...
    山有木兮有木兮閱讀 8,202評論 0 4
  • 現(xiàn)在, 多核CPU已經(jīng)非常普及了, 但是, 即使過去的單核CPU, 也可以執(zhí)行多任務(wù)。 CPU執(zhí)行代碼都是順序執(zhí)行...
    LittlePy閱讀 4,932評論 0 3
  • 進(jìn)程進(jìn)程的概念是需要理解的,進(jìn)程是操作系統(tǒng)中正在運(yùn)行的一個程序?qū)嵗?,操作系統(tǒng)通過進(jìn)程操作原語來對其進(jìn)行調(diào)度。操作系...
    zhile_doing閱讀 556評論 0 0
  • 進(jìn)程的基本概念 進(jìn)程是程序的一次執(zhí)行,每個進(jìn)程都有自己的地址空間,內(nèi)存,數(shù)據(jù)棧以及其他記錄其運(yùn)行軌跡的輔助數(shù)據(jù)。多...
    XYZeroing閱讀 1,258評論 0 13

友情鏈接更多精彩內(nèi)容