1. python多進(jìn)程簡(jiǎn)述

一、多進(jìn)程概述

  • 程序:是一個(gè)指令的集合
  • 進(jìn)程:正在執(zhí)行的程序;或者說:當(dāng)你運(yùn)行一個(gè)程序,你就啟動(dòng)了一個(gè)進(jìn)程
  • 編寫完的代碼,沒有運(yùn)行時(shí),稱為程序,正在運(yùn)行的代碼,稱為進(jìn)程;
  • 程序是死的(靜態(tài)的),進(jìn)程是活的(動(dòng)態(tài)的)
  • 操作系統(tǒng)輪流讓各個(gè)任務(wù)交替執(zhí)行,由于CPU的執(zhí)行速度實(shí)在是太快了,我們感覺就像所有任務(wù)都在同時(shí)執(zhí)行一樣;
  • 多進(jìn)程中,每個(gè)進(jìn)程中所有數(shù)據(jù)(包括全局變量)都各自擁有一份,互相不影響。
  • 程序啟動(dòng)運(yùn)行時(shí),首先會(huì)創(chuàng)建一個(gè)主進(jìn)程
  • 在主進(jìn)程(父進(jìn)程)下,我們可以創(chuàng)建新的進(jìn)程(子進(jìn)程),子進(jìn)程依賴于主進(jìn)程,如果主進(jìn)程結(jié)束,程序會(huì)退出
  • 創(chuàng)建子進(jìn)程時(shí)會(huì)在子進(jìn)和空間中復(fù)制一份主進(jìn)程的代碼,全局變量在多個(gè)子進(jìn)程之間不共享,進(jìn)程之間的數(shù)據(jù)是獨(dú)立的,默認(rèn)情況下互不影響。

二、通過調(diào)用multiprocessing.Process實(shí)現(xiàn)多進(jìn)程

  • Python提供了非常好用的多進(jìn)程包multiprocessing,借助這個(gè)包,可以輕松完成從單進(jìn)程到并發(fā)執(zhí)行的轉(zhuǎn)換。
  • multiprocessing模塊提供了一個(gè)Process類來創(chuàng)建一個(gè)進(jìn)程對(duì)象。
  • 如果用循環(huán)創(chuàng)建多個(gè)進(jìn)程時(shí),可以把多個(gè)子進(jìn)程對(duì)象加到list中,在循環(huán)外再循環(huán)執(zhí)行l(wèi)ist中的每個(gè)對(duì)象的join()方法以達(dá)到主進(jìn)程等待所有子進(jìn)程都結(jié)束。
import timefrom multiprocessing import Process
def sing(name):
    for i in range(10):
        print(name+"唱歌")
        time.sleep(1)

def dance():
    for i in range(10):
        print("跳舞")
        time.sleep(1)

if __name__ == '__main__':
    p1 = Process(target=sing, args=('林志凌',), name="sing")
    p2 = Process(target=dance , name="dance")
    p1.start()
    print(p1.name)
    p2.start()
    print(p2.name)
    p1.join() #join() 主進(jìn)程等待子進(jìn)程結(jié)束
    p2.join()
  • Process 類常用方法
  • p.start():啟動(dòng)進(jìn)程,并調(diào)用該子進(jìn)程中的p.run()
  • p.run():進(jìn)程啟動(dòng)時(shí)運(yùn)行的方法,正是它去調(diào)用target指定的函數(shù),我們自定義類的類中一定要實(shí)現(xiàn)該方法
  • p.terminate() 強(qiáng)制終止進(jìn)程p,不會(huì)進(jìn)行任何清理操作
  • p.is_alive() 如果p仍然運(yùn)行,返回True,用于判斷進(jìn)程是否在運(yùn)行
  • p.join([timeout]) 主進(jìn)程等待子進(jìn)程結(jié)束,timeout是可選的超時(shí)時(shí)間。
  • Process類常用屬性
  • name:當(dāng)前進(jìn)程實(shí)例別名,默認(rèn)為Process-N,N從1開始遞增
  • pid:當(dāng)前進(jìn)程實(shí)例的PID值

三、通過繼承Process類創(chuàng)建多進(jìn)程

import multiprocessing
import time

class ClockProcess(multiprocessing.Process):
    def __init__(arg):
        super().__init__()
        self.arg = arg
    def run(self):
        n = self.arg
        while n>0:
            print(n)
            time.sleep(1)
            n -= 1

if __name__ == '__main__':
    p = ClockProcess(5)
    p.start()
    p.join()

四、進(jìn)程池-Pool

  • 進(jìn)程池:用來創(chuàng)建多個(gè)進(jìn)程
  • 當(dāng)需要?jiǎng)?chuàng)建的子進(jìn)程數(shù)量不多時(shí),可以直接利用multiprocessing中的Process動(dòng)態(tài)生成多個(gè)進(jìn)程,但如果要?jiǎng)?chuàng)建的子進(jìn)程數(shù)很多時(shí),此時(shí)可以用到multiprocessing模塊提供的Pool
  • 初始化Pool時(shí),可以指定一個(gè)最大進(jìn)程數(shù), 當(dāng)有新的請(qǐng)求提交到Pool中時(shí),如果進(jìn)程池還沒有滿,那么就會(huì)創(chuàng)建一個(gè)新的進(jìn)程用來執(zhí)行該請(qǐng)求;但如果進(jìn)程池中的進(jìn)程數(shù)已經(jīng)達(dá)到最大值,那么該請(qǐng)求就會(huì)等待,直到進(jìn)程池中有進(jìn)程結(jié)束,才會(huì)創(chuàng)建新的進(jìn)程來執(zhí)行。
from multiprocessing import Pool
import random, time
def work(num):
    print(random.random() * num)
    time.sleep(3)

if __name__ == '__main__':
    po = Pool(4)  #如果不寫默認(rèn)為當(dāng)前CPU核數(shù)
    for i in range(10):
        po.apply_async(work, (i,))
    po.close()
    po.join()
  • multiprocessing.Pool常用函數(shù)解析:
  • apply_async(self, func, args=(), kwds={}, callback=None, error_callback=None):使用非阻塞方式調(diào)用fun(并行執(zhí)行,阻塞方式必須等上一個(gè)進(jìn)程退出才能執(zhí)行下一個(gè)進(jìn)程)args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)列表;
  • apply(func[, args[, kwds]]) (了解即可幾乎不用)使用阻塞的方式調(diào)用func
  • close():關(guān)閉Pool,使其不再接受新的任務(wù);
  • terminate():不管任務(wù)是否完成,立即終止;
  • join():主進(jìn)程阻塞,等待子進(jìn)程退出,必須在close()或terminate之后使用;

五、 進(jìn)程間通信-Queue

  • 可以使用multiprocessing模塊的Queue實(shí)現(xiàn)多進(jìn)程間的數(shù)據(jù)傳遞
  • 初始化Queue()對(duì)象時(shí)(例如:q = Queue()),若括號(hào)中沒有指定最大可接收的消息數(shù)量,或數(shù)量為負(fù)值,那么就代表可接受的消息數(shù)量沒有上限
  • 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)值為True
    • 如果block使用默認(rèn)值,且沒有設(shè)置timeout(單位移),消息隊(duì)列如果為空,此時(shí)程序?qū)⒈蛔枞ㄍT谧x取狀態(tài)),直到從消息隊(duì)列讀到消息為止,如果設(shè)置了timeout,則會(huì)等待timeout秒,若還沒讀取到任何消息,則拋出“Queue.Empty”異常
    • 如果block值為False,消息隊(duì)列如果為空,則會(huì)立刻拋出“Queue.Empty”異常。
  • Queue.get_nowait() :相當(dāng)于Queue.get(False)
  • Queue.put(item, [block, [, timeout]]) :將item消息寫入隊(duì)列,block默認(rèn)值為True
    • 如果block使用默認(rèn)值,且沒有設(shè)置timeout,消息隊(duì)列如果已沒有空間寫入,此時(shí)程序?qū)⒈蛔枞ㄍT趯懭霠顟B(tài)),直到從消息隊(duì)列中騰出空間為止,如果設(shè)置了True和timeout,則會(huì)等待timeout秒,若還沒有空間,則拋出”Queue.Full“異常
    • 如果block值為False,消息隊(duì)列如果沒有空間可寫入,則會(huì)立刻拋出”Queue.Full“異常
  • Queue.put_nowait(itme) :相當(dāng)于Queue.put(item, False)
import time
from multiprocessing import Queue, Process

def write(q)
    for value in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']:
        print("開始寫入:", value)
        q.put(value)
        time.sleep(1)

def read(q):
    while True:
        if not q.empty():
            print("讀取到的是", q.get())
            time.sleep(1)
        else:
            break

if __name__ == '__main__':
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    pw.start()
    time.sleep(1)
    pr.start()
    pw.join()
    pr.join()
    print('接收完畢!')

六、進(jìn)程池之間通信- Manager().Queue()

  • 進(jìn)程池之間通信,就需要使用multiprocessing.Manager()中的Queue()而不是multiprocessing.Queue()
  • 否則會(huì)得到一條如下錯(cuò)誤信息:

RuntimeError: Queue objects should only be shared between processes through inheritance.

import time 
from multiprocessing import Manager, Pool

def writer(q):
    for i in "welcome":
        print("開始寫入", i)
        q.put(i)

def reader(q):
    time.sleep(3)
    for i in range(q.qsize()):
        print("得到消息", q.get())

if __name__ == "__main__":
    print("主進(jìn)程啟動(dòng)")
    q = Manager().Queue()
    po = Pool()
    po.apply_async(writer, (q,))
    po.apply_async(reader, (q,))
    po.close()
    po.join()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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