Python的多進程模塊multiprocessing

眾所周知滥比,Python中不存在真正的多線程,Python中的多線程是一個并發(fā)過程祷肯。如果想要并行的執(zhí)行程序,充分的利用cpu資源(cpu核心)疗隶,還是需要使用多進程解決的佑笋。其中multiprocessing模塊應該是Python中最常用的多進程模塊了。

創(chuàng)建進程

基本上multiprocessing這個模塊和threading這個模塊用法是相同的斑鼻,也是可以通過函數(shù)和類創(chuàng)建進程蒋纬。

""" 案例1:函數(shù)式創(chuàng)建進程 """

import multiprocessing
import time


# 進程執(zhí)行函數(shù)
def run(num):
    time.sleep(1)
    print(f'i am process{num}')


if __name__ == '__main__':
    # 獲取開始的時間戳
    start = time.time()
    # 存放進程的列表,用于阻塞進程
    process_list = list()
    # 創(chuàng)建4個進程坚弱,并將每個創(chuàng)建好的進程對象放到process_list中
    for i in range(1, 5):
        process = multiprocessing.Process(target=run, args=(i,))
        # 啟動該進程
        process.start()
        process_list.append(process)

    # 只有進程全部結(jié)束颠锉,再向下執(zhí)行
    for j in process_list:
        j.join()

    # 結(jié)束的時間戳
    end = time.time()
    # 打印該程序運行了幾秒
    print(end-start)

# i am process1
# i am process2
# i am process3
# i am process4
# 1.122110366821289

上述案例基本上就是筆者搬用了上篇文章多線程的案例,可見其使用的相似之處史汗。導入multiprocessing后實例化Process就可以創(chuàng)建一個進程,參數(shù)的話也是和多線程一樣拒垃,target放置進程執(zhí)行函數(shù)停撞,args存放該函數(shù)的參數(shù)。

""" 案例2:類繼承創(chuàng)建進程 """

import multiprocessing
import time


# 繼承Process悼瓮,轉(zhuǎn)變?yōu)檫M程類
class MyProcess(multiprocessing.Process):
    def __init__(self, process_id):
        # 必須實現(xiàn)Process類的init方法
        super().__init__()
        self.process_id = process_id

    # 重寫執(zhí)行函數(shù)
    def run(self):
        time.sleep(1)
        print(f'i am process{self.process_id}')


if __name__ == '__main__':
    # 獲取開始的時間戳
    start = time.time()
    # 存放進程的列表戈毒,用于阻塞進程
    process_list = list()
    # 創(chuàng)建4個進程,并將每個創(chuàng)建好的進程對象放到process_list中
    for i in range(1, 5):
        process = MyProcess(i)
        # 啟動該進程
        process.start()
        process_list.append(process)

    # 只有進程全部結(jié)束横堡,再向下執(zhí)行
    for j in process_list:
        j.join()

    # 結(jié)束的時間戳
    end = time.time()
    # 打印該程序運行了幾秒
    print(end - start)

# i am process1
# i am process2
# i am process3
# i am process4
# 1.1184189319610596

使用類來創(chuàng)建進程也是需要先繼承multiprocessing.Process并且實現(xiàn)其init方法埋市。

進程池

Pool可以提供指定數(shù)量的進程,供用戶調(diào)用命贴,當有新的請求提交到pool中時道宅,如果池還沒有滿,那么就會創(chuàng)建一個新的進程用來執(zhí)行該請求胸蛛。

但如果池中的進程數(shù)已經(jīng)達到規(guī)定最大值污茵,那么該請求就會等待,直到池中有進程結(jié)束葬项,才會創(chuàng)建新的進程泞当。

""" 案例3:進程池Pool """

import multiprocessing
import time


# 進程執(zhí)行函數(shù)
def func(msg):
    print('process start...', msg)
    time.sleep(3)
    print('process end...')


if __name__ == '__main__':
    print('ready~~~~~~~~~~~~~~~~~go~~~~~')

    # 創(chuàng)建進程池,最大進程數(shù)量為3
    pool = multiprocessing.Pool(processes=3)
    for i in range(5):
        msg = f'hello {i}'
        # 以非阻塞的方式民珍,維持執(zhí)行的進程總數(shù)為processes并在進程結(jié)束后自動添加新的進程
        pool.apply_async(func, (msg,))

    # 阻止后續(xù)任務(wù)提交到進程池
    pool.close()
    # 等待工作進程結(jié)束
    pool.join()

    print('game~~~~~~~~~~~~~~~~~over~~~~~')

# ready~~~~~~~~~~~~~~~~~go~~~~~
# process start... hello 0
# process start... hello 1
# process start... hello 2
# process end...
# process start... hello 3
# process end...
# process end...
# process end...
# game~~~~~~~~~~~~~~~~~over~~~~~

需要注意的是襟士,在調(diào)用join方法阻塞進程前盗飒,需要先調(diào)用close方法,陋桂,否則程序會出錯逆趣。

在上述案例中,提到了非阻塞章喉,當把創(chuàng)建進程的方法換為pool.apply(func, (msg,))時汗贫,就會阻塞進程,出現(xiàn)下面的狀況秸脱。

# ready~~~~~~~~~~~~~~~~~go~~~~~
# process start... hello 0
# process end...
# process start... hello 1
# process end...
# process start... hello 2
# process end...
# process start... hello 3
# process end...
# process start... hello 4
# process end...
# game~~~~~~~~~~~~~~~~~over~~~~~

進程隊列

在multiprocessing模塊中還存在Queue對象何缓,這是一個進程的安全隊列录平,近似queue.Queue。隊列一般也是需要配合多線程或者多進程使用。

下列案例是一個使用進程隊列實現(xiàn)的生產(chǎn)者消費者模式遥缕。

""" 案例4:基于進程隊列的生產(chǎn)者消費者模式 """

import random
import time
import multiprocessing


# 生產(chǎn)者
def producer(queue):
    for i in range(10):
        time.sleep(random.randint(1, 3))
        res = f'物品{i}'
        # 入隊
        queue.put(res)
        print(f'{multiprocessing.current_process().name}生產(chǎn){res}')


# 消費者
def consumer(queue):
    while True:
        # 出隊
        res = queue.get()
        time.sleep(random.randint(1, 3))
        print(f'{multiprocessing.current_process().name}消費{res}')


if __name__ == '__main__':
    # 生產(chǎn)消費隊列
    queue = multiprocessing.Queue()
    # 創(chuàng)建生產(chǎn)進程
    process1 = multiprocessing.Process(target=producer, args=(queue,))
    # 進程名
    process1.name = 'process_1'

    # 創(chuàng)建消費進程
    process2 = multiprocessing.Process(target=consumer, args=(queue,))
    # 進程名
    process2.name = 'process_2'

    print('程序開始!8∩摇握巢!')
    # 啟動進程
    process1.start()
    process2.start()

# 程序開始!5呵搿旭寿!
# process_1生產(chǎn)物品0
# process_1生產(chǎn)物品1
# process_2消費物品0
# process_1生產(chǎn)物品2
# process_2消費物品1
# process_1生產(chǎn)物品3
# ......

管道

multiprocessing支持兩種進程間的通信,其中一種便是上述案例的隊列崇败,另一種則稱作管道盅称。在官方文檔的描述中,multiprocessing中的隊列是基于管道實現(xiàn)的后室,并且擁有更高的讀寫效率缩膝。

管道可以理解為進程間的通道,使用Pipe([duplex])創(chuàng)建岸霹,并返回一個元組(conn1,conn2)疾层。如果duplex被置為True(默認值),那么該管道是雙向的贡避,如果duplex被置為False痛黎,那么該管道是單向的,即conn1只能用于接收消息刮吧,而conn2僅能用于發(fā)送消息舅逸。

其中conn1、conn2表示管道兩端的連接對象皇筛,每個連接對象都有send()和recv()方法琉历。send和recv方法分別是發(fā)送和接受消息的方法。例如,可以調(diào)用conn1.send發(fā)送消息旗笔,conn1.recv接收消息彪置。如果沒有消息可接收,recv方法會一直阻塞蝇恶。如果管道已經(jīng)被關(guān)閉拳魁,那么recv方法會拋出EOFError。

""" 案例5:管道 """

import multiprocessing
import random
import time


# 發(fā)送數(shù)據(jù)
def proc_send(pipe, data):
    for d in data:
        pipe.send(d)
        print(f'{multiprocessing.current_process().name}發(fā)送了數(shù)據(jù)bdjrfrh')
        time.sleep(random.random())


# 接收數(shù)據(jù)
def proc_recv(pipe):
    while True:
        print(f'{multiprocessing.current_process().name}接收了數(shù)據(jù){pipe.recv()}')
        time.sleep(random.random())


if __name__ == '__main__':
    # 創(chuàng)建管道
    pipe1, pipe2 = multiprocessing.Pipe()
    # 數(shù)據(jù)
    data = [i for i in range(10)]
    # 創(chuàng)建進程process1
    process1 = multiprocessing.Process(target=proc_send, args=(pipe1, data))
    process1.name = 'process_1'
    # 創(chuàng)建進程process1
    process2 = multiprocessing.Process(target=proc_recv, args=(pipe2,))
    process2.name = 'process_2'

    # 啟動進程
    process1.start()
    process2.start()

    # 阻塞進程
    process1.join()
    process2.join()

# process_1發(fā)送了數(shù)據(jù)0
# process_2接收了數(shù)據(jù)0
# process_1發(fā)送了數(shù)據(jù)1
# process_2接收了數(shù)據(jù)1
# process_1發(fā)送了數(shù)據(jù)2
# process_2接收了數(shù)據(jù)2
# process_1發(fā)送了數(shù)據(jù)3
# process_2接收了數(shù)據(jù)3
# ......

關(guān)于multiprocessing模塊其實還有很多實用的類和方法撮弧,由于篇幅有限(懶),筆者就先寫到這里潘懊。該模塊其實用起來很像threading模塊,像鎖對象和守護線程(進程)等multiprocessing模塊也是有的贿衍,使用方法也近乎相同授舟。

如果想要更加詳細的了解multiprocessing模塊,請參考官方文檔贸辈。

# multiprocessing --- 基于進程的并行
https://docs.python.org/zh-cn/3/library/multiprocessing.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末释树,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子擎淤,更是在濱河造成了極大的恐慌奢啥,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘴拢,死亡現(xiàn)場離奇詭異桩盲,居然都是意外死亡,警方通過查閱死者的電腦和手機席吴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門正驻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抢腐,你說我怎么就攤上這事〗蠼唬” “怎么了迈倍?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捣域。 經(jīng)常有香客問我啼染,道長,這世上最難降的妖魔是什么焕梅? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任迹鹅,我火速辦了婚禮,結(jié)果婚禮上贞言,老公的妹妹穿的比我還像新娘斜棚。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布弟蚀。 她就那樣靜靜地躺著蚤霞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪义钉。 梳的紋絲不亂的頭發(fā)上昧绣,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天,我揣著相機與錄音捶闸,去河邊找鬼夜畴。 笑死,一個胖子當著我的面吹牛删壮,可吹牛的內(nèi)容都是我干的贪绘。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼醉锅,長吁一口氣:“原來是場噩夢啊……” “哼兔簇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硬耍,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤垄琐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后经柴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狸窘,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年坯认,在試婚紗的時候發(fā)現(xiàn)自己被綠了翻擒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡牛哺,死狀恐怖陋气,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情引润,我是刑警寧澤巩趁,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站淳附,受9級特大地震影響议慰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奴曙,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一别凹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洽糟,春花似錦炉菲、人聲如沸堕战。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽践啄。三九已至,卻和暖如春沉御,著一層夾襖步出監(jiān)牢的瞬間屿讽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工吠裆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伐谈,地道東北人。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓试疙,卻偏偏與公主長得像诵棵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子祝旷,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351