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

#原創,轉載請聯繫數據結構

咱們都知道,主進程和子進程之間不能共享全局變量。那麼他們之間怎麼實現通訊呢?函數

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

1.隊列的簡單介紹:線程

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

 

2.怎麼建立一個隊列:blog

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是什麼緣由呢?ip

我已經把3個東西放進隊列了啊,爲何還會顯示隊伍爲空是對的呢?緣由就是,put函數還沒來的及把數據放進隊列裏,你就打印了出來了。get

而後你就會問,爲何,還沒把數據放進隊列裏,就會顯示隊伍是否爲盡是對的呢?

緣由就是,這是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(),運行多幾回,你會知道爲何的。

相關文章
相關標籤/搜索