[英]python multiprocessing shared queue re-ordering
我有一台服務器和幾個客戶端。 它們都共享一個任務,並且結果為multiprocessing.Queue。 但是,每當客戶端完成一項任務並將結果放入結果隊列時,我都希望服務器查看結果,然后基於此結果對任務隊列重新排序。
這當然意味着將所有內容從任務隊列中彈出並重新添加。 在此重新排序過程中,我希望客戶端阻止接觸任務隊列。 我的問題是我如何讓服務器識別何時將任務添加到結果隊列中,並通過鎖定任務隊列並在保護隊列的同時重新排序來做出反應。 不變的是,服務器必須在返回每個結果之后重新排序,然后客戶端才能獲得新任務。
我想一個簡單的(但是錯誤的)方法是讓multiprocessing.Value充當布爾值,並且每當添加結果時,客戶端就會將其翻轉為True,這意味着已經添加了結果。 服務器可以輪詢以獲得該值,但最終它可能會錯過輪詢之間添加另一個結果的另一個客戶端。
任何想法表示贊賞。
**'multithreading'標簽只是因為它與線程中的思想非常相似,我認為這里的進程/線程區別並不重要。
讓我們嘗試一些代碼-有些進步總比沒有好;-)問題的一部分是確保如果結果隊列中有內容,那么什么也不會從任務隊列中獲取,對吧? 因此,隊列緊密相連。 此方法將兩個隊列置於鎖的保護之下,並使用“條件”來避免進行輪詢的任何需要:
設置,在服務器中完成。 必須將taskQ
, resultQ
, taskCond
和resultCond
傳遞給客戶端進程(不需要顯式傳遞lock
-它包含在條件中):
import multiprocessing as mp
taskQ = mp.Queue()
resultQ = mp.Queue()
lock = mp.Lock()
# both conditions share lock
taskCond = mp.Condition(lock)
resultCond = mp.Condition(lock)
客戶得到任務; 所有客戶端都使用此功能。 請注意,只要結果隊列中包含某些內容,就不會使用該任務:
def get_task():
taskCond.acquire()
while taskQ.qsize() == 0 or resultQ.qsize():
taskCond.wait()
# resultQ is empty and taskQ has something
task = taskQ.get()
taskCond.release()
return task
客戶有結果:
with resultCond:
resultQ.put(result)
# only the server waits on resultCond
resultCond.notify()
服務器循環:
resultCond.acquire()
while True:
while resultQ.qsize() == 0:
resultCond.wait()
# operations on both queues in all clients are blocked now
# ... drain resultQ, reorder taskQ ...
taskCond.notify_all()
筆記:
qsize()
通常是概率性的,但是由於所有隊列操作都是在持有鎖的同時完成的,因此在這種情況下它是可靠的。
實際上,由於所有隊列操作均受此處自己的鎖保護,因此實際上無需使用mp.Queue
。 例如, mp.Manager().list()
也可以工作(任何共享結構)。 也許當您重新安排任務時,列表會更容易使用?
我不喜歡的一部分:當服務器執行taskCond.notify_all()
,某些客戶端可能正在等待獲取新任務,而另一些客戶端可能正在等待返回新結果。 它們可以以任何順序運行。 任何等待返回結果的客戶端都有機會,所有等待獲取任務的客戶端都會阻塞,但是在此之前,任務將被消耗。 當然,這里的“問題”是我們不知道有什么新結果要等到實際添加到結果隊列中。
對於最后一個,也許將“客戶有結果”代碼更改為:
resultQ.put(result)
with resultCond:
resultCond.notify()
會更好。 不確定。 這確實使推理變得非常困難,因為所有隊列操作都是在鎖的保護下完成的,這不再是事實。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.