多进程 queue 的共享和重新排序

99 阅读2分钟

我们有一个服务器和几个客户端,它们都共享一个任务和结果的多进程 Queue。但是,每当一个客户端完成一个任务并把结果放入结果 Queue 时,我们希望服务器能够查看结果,并根据结果重新排序任务 Queue。这意味着当然要先将任务 Queue 中的所有内容弹出,然后再重新添加。在此重新排序的过程中,我们希望客户端阻止触摸任务 Queue。我们的问题是如何让服务器识别何时将任务添加到结果 Queue 中,并通过锁定任务 Queue 和重新排序来做出反应,同时保护 Queue。不变的是,服务器必须在客户端获得新任务之前重新排序每次返回的结果。

huake_00198_.jpg 我们认为有一个简单(但错误)的方法是使用一个 multiprocessing.Value 作为布尔值,每当添加结果时,客户端将该布尔值翻转为 True,表示已添加结果。服务器可以通过轮询获取此值,但最终它可能会错过在轮询和添加另一个结果之间插入的另一个客户端。

解决方案

可以使用以下代码来解决问题:

import multiprocessing as mp

task_queue = mp.Queue()
result_queue = mp.Queue()
lock = mp.Lock()
task_condition = mp.Condition(lock)
result_condition = mp.Condition(lock)

def get_task():
    task_condition.acquire()
    while task_queue.qsize() == 0 or result_queue.qsize():
        task_condition.wait()
    task = task_queue.get()
    task_condition.release()
    return task

def put_result(result):
    with result_condition:
        result_queue.put(result)
        result_condition.notify()

def server_loop():
    result_condition.acquire()
    while True:
        while result_queue.qsize() == 0:
            result_condition.wait()
        # 操作所有客户端中的两个队列现在都被阻止
        # ... 清空结果队列,重新排序任务队列 ...
        task_condition.notify_all()

# 客户端进程:
client_process = mp.Process(target=client_main)
client_process.start()

# 服务器进程:
server_process = mp.Process(target=server_main)
server_process.start()

与该解决方案一起使用的代码示例如下:

# 在服务器中:
task_queue = mp.Queue()
result_queue = mp.Queue()
lock = mp.Lock()
task_condition = mp.Condition(lock)
result_condition = mp.Condition(lock)

# 在客户端中:
def get_task():
    task_condition.acquire()
    while task_queue.qsize() == 0 or result_queue.qsize():
        task_condition.wait()
    task = task_queue.get()
    task_condition.release()
    return task

def put_result(result):
    with result_condition:
        result_queue.put(result)
        result_condition.notify()

# 在服务器中:
def server_loop():
    result_condition.acquire()
    while True:
        while result_queue.qsize() == 0:
            result_condition.wait()
        # 操作所有客户端中的两个队列现在都被阻止
        # ... 清空结果队列,重新排序任务队列 ...
        task_condition.notify_all()

# 在客户端进程中:
client_process = mp.Process(target=client_main)
client_process.start()

# 在服务器进程中:
server_process = mp.Process(target=server_main)
server_process.start()

希望此解决方案对解决您的问题有所帮助!