主進程與子進程之間的通信


#原創,轉載請聯系

我們都知道,主進程和子進程之間不能共享全局變量。那么他們之間怎么實現通信呢?

這就需要用到Queue(隊列)了。

1.隊列的簡單介紹:

隊列是常見的數據結構,采用先進先出的原則。從隊列的尾部存數據,從隊列的頭部取數據。

 

2.怎么創建一個隊列:

q = multiprocessing.Queue()

括號里面可以傳進去一個參數,表示隊列的長度。

 

3.隊列會出現的BUG?

import multiprocessing
import time

q = multiprocessing.Queue(3)
q.put("1")
q.put("2")
q.put("3")
print("隊列是否為滿?",q.full())
print("隊列是否為空?",q.empty())

輸出:
隊列是否為滿? True
隊列是否為空? True(False)

注意輸出的地方。運行多幾次,輸出結果會不同。有時候隊列是否為空是True,有時候隊列是否為False。出現True是什么原因呢?

我已經把3個東西放進隊列了啊,為什么還會顯示隊伍為空是對的呢?原因就是,put函數還沒來的及把數據放進隊列里,你就打印了出來了。

然后你就會問,為什么,還沒把數據放進隊列里,就會顯示隊伍是否為滿是對的呢?

原因就是,這是Queue內部的一個機制。

內部的機制應該是這樣子的,舉個例子,有兩個教室,兩個教室都分別有一個指揮官。第一個教室的指揮官叫3個同學去第二個教室,然后他就記在本子上了,有3個同學已經去了第二個教室,對應的是,隊列已經滿了,打印輸出,隊列是否為滿是真的。

但是這3個學生還沒走到第二個教室,第二個教室的指揮官就在本子上寫,沒有人來,對應的是,隊列是空的,打印輸出,隊列是否是空的是真的。

但是學生如果走得快點,第二個教室的指揮官在本子上寫,哎呀,有3個學生來了,對應的是,隊列是滿的,打印輸出,隊列是否是空的是假的。

 

4.隊列的阻塞問題

如果一個隊列最大的長度是3個,你put進去了4個。那么最后一個put的很理所當然的要等待。

但是,

最后一個等待的時候,會阻塞,使下面的代碼不能運行。

import multiprocessing
import time

q = multiprocessing.Queue(3)
q.put("1")
q.put("2")
q.put("3")
q.put("4")
print("隊列是否為滿?",q.full())
print("隊列是否為空?",q.empty())

輸出:
(輸出為空,但是程序並沒有結束)

上述代碼中,隊列的最大長度是3,放進了3個后,正想放第4個,但是放不下了。那么第4個就只有在這里等待。但是他不僅要等待,還是阻塞狀態。只有等他運行了,他下面的代碼才能繼續運行。

還有另一種情況:

不僅僅是沒地方放的時候會造成阻塞,如果隊列為空,你要在里面拿東西,也會造成阻塞。

import multiprocessing

q = multiprocessing.Queue(3)
q.get()
print("走開")
print("我要吃漢堡包")

輸出:
(內容為空,且進程沒有結束)

 

5.進程之間的通信

說了這么多,該開始講一下進程之間怎么實現通信的了。

實現目標:我們在主進程中創建兩個子進程,一個用來把數據放在隊列里,一個用來在隊列里取數據,這樣一來就實現了通信的功能了吧。

import multiprocessing
import time


def put_data(queue):
    for i in "abcde":
        queue.put(i)
        time.sleep(0.5)
        print("把數據%s放在隊列里:" % i)

def get_data(queue):
    while not queue.empty():
        time.sleep(0.5)
        data = queue.get()
        print("從隊列拿到數據:%s" % data)

if __name__ == '__main__':
    queue = multiprocessing.Queue(5)
    p1 = multiprocessing.Process(target=put_data,args=(queue,))
    p1.start()
    p1.join()  
    p2 = multiprocessing.Process(target=get_data, args=(queue,))
    p2.start()
    p2.join()  # 如果不加上p1.join和p2.join會發生很奇怪的BUG,get_data函數的里面的queue.empty會出現BUG,原理就是第3.所說的。
會導致p2線程誤判為空,還沒取完數據就結束任務了。


輸出:
把數據a放在隊列里:
把數據b放在隊列里:
把數據c放在隊列里:
把數據d放在隊列里:
把數據e放在隊列里:
從隊列拿到數據:a
從隊列拿到數據:b
從隊列拿到數據:c
從隊列拿到數據:d
從隊列拿到數據:e

注意紅色字的說明!去掉p1.join()和p2.join(),運行多幾次,你會知道為什么的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM