Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python多处理共享队列重排序_Python_Multithreading_Client Server_Queue_Multiprocessing - Fatal编程技术网

python多处理共享队列重排序

python多处理共享队列重排序,python,multithreading,client-server,queue,multiprocessing,Python,Multithreading,Client Server,Queue,Multiprocessing,我有一个服务器和几个客户端。它们都共享一个任务和结果multiprocessing.Queue。但是,每当客户机完成任务并将结果放入结果队列时,我希望服务器查看结果,并在此基础上重新排序任务队列 这当然意味着从任务队列中弹出所有内容并重新添加。在这个重新排序过程中,我希望客户端阻止触摸任务队列。我的问题是如何让服务器识别何时将任务添加到结果队列,并通过锁定任务队列和重新排序来做出反应,同时保护队列。不变的是,在客户端获得新任务之前,服务器必须在返回的每个结果之后重新排序 我认为一种简单(但错误)

我有一个服务器和几个客户端。它们都共享一个任务和结果multiprocessing.Queue。但是,每当客户机完成任务并将结果放入结果队列时,我希望服务器查看结果,并在此基础上重新排序任务队列

这当然意味着从任务队列中弹出所有内容并重新添加。在这个重新排序过程中,我希望客户端阻止触摸任务队列。我的问题是如何让服务器识别何时将任务添加到结果队列,并通过锁定任务队列和重新排序来做出反应,同时保护队列。不变的是,在客户端获得新任务之前,服务器必须在返回的每个结果之后重新排序

我认为一种简单(但错误)的方法是使用多处理。值作为布尔值,每当添加结果时,客户端将其翻转为True,这意味着添加了一个结果。服务器可以轮询以获取此值,但最终可能会错过另一个客户端,该客户端在轮询和添加另一个结果之间进行访问

任何想法都值得赞赏


**“multithreading”标签只是因为它的思想与线程非常相似,我认为这里的进程/线程区别并不重要。

让我们尝试一些代码-有些进展比没有要好;-)问题的一部分是确保如果结果队列中有内容,则不会从任务队列中获取任何内容,对吗?因此,队列是紧密相连的。此方法将两个队列置于锁的保护下,并使用条件避免任何轮询需要:

安装,在服务器中完成
taskQ
resultQ
taskCond
resultCond
必须传递给客户端进程(
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
    s。例如,一个
    mp.Manager().list()
    也可以工作(任何共享结构)。当你重新安排任务时,也许一个列表更容易处理

  • 有一部分我不太喜欢:当服务器执行
    taskCond.notify_all()
    时,一些客户端可能正在等待获取新任务,而其他客户端可能正在等待返回新结果。它们可以按任何顺序运行。只要任何等待返回结果的客户端有机会,所有等待获取任务的客户端都将被阻止,但在此之前,任务将被消耗。当然,这里的“问题”是,我们不知道在将某些内容实际添加到结果队列之前,新结果正在等待

  • 对于最后一个,可能会将“client has result”代码更改为:


    那就更好了。不确定。这确实使推理变得更加困难,因为所有的队列操作都是在我们的锁的保护下完成的,这已不再是事实。

    我不确定您对哪一部分有问题。问题是如何保护队列或如何在新结果到达时通知服务器?其余时间服务器需要做什么?我假设它不能只是阻塞result_queue.get()。服务器是侦听客户端连接的设备,也是存储内存所在的位置。进程(可能是服务器)可以侦听结果队列,但它必须做出反应,并在成功时立即尝试锁定任务队列,这与轮询情况相同,实际上,我想出了一些非常相似的东西。您提到的关键观点是,由于不变量,队列在某种意义上是绑定在一起的。因此,一旦锁定,它们就不需要是特殊的线程安全数据结构。最后,我让服务器侦听器线程(在客户端连接后被调度以侦听客户端套接字的线程)实际执行重新排序。这是最好的,因为这些侦听器实际上响应已完成的任务。它们的阻塞重新排序和结果分派真的一起进行。虽然我承认我不太了解多处理。条件类的用法-为什么不使用常规锁?酷!条件有一个学习曲线,但一旦学习了条件,编写正确的并行安全代码就非常容易了。这就是为什么,例如Python的
    threading.py
    在条件之上构建事件、障碍和信号量。一个关键的好处是——如上所述——条件中的底层锁永远不会保持很长时间。代码很快释放锁,或者很快执行.wait()(释放锁,并在.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()
    
    resultQ.put(result)
    with resultCond:
        resultCond.notify()