【问题标题】:Python multiprocessing.Queue deadlocks on put and getPython multiprocessing.Queue 上的 put 和 get 死锁
【发布时间】:2011-03-08 11:44:40
【问题描述】:

这段代码遇到了死锁问题:


def _entropy_split_parallel(data_train, answers_train, weights):
    CPUS = 1 #multiprocessing.cpu_count()
    NUMBER_TASKS = len(data_train[0])
    processes = []

    multi_list = zip(data_train, answers_train, weights)

    task_queue = multiprocessing.Queue()
    done_queue = multiprocessing.Queue()

    for feature_index in xrange(NUMBER_TASKS):
        task_queue.put(feature_index)

    for i in xrange(CPUS):
        process = multiprocessing.Process(target=_worker, 
                args=(multi_list, task_queue, done_queue))
        processes.append(process)
        process.start()

    min_entropy = None
    best_feature = None
    best_split = None
    for i in xrange(NUMBER_TASKS):
        entropy, feature, split = done_queue.get()
        if (entropy < min_entropy or min_entropy == None) and entropy != None:
            best_feature = feature
            best_split = split

    for i in xrange(CPUS):
        task_queue.put('STOP')

    for process in processes:
        process.join()

    return best_feature, best_split


def _worker(multi_list, task_queue, done_queue):
    feature_index = task_queue.get()
    while feature_index != 'STOP':
        result = _entropy_split3(multi_list, feature_index)
        done_queue.put(result)
        feature_index = task_queue.get()

当我运行我的程序时,它可以正常运行多次_entropy_split_parallel,但最终会死锁。父进程阻塞done_queue.get(),工作进程阻塞done_queue.put()。由于发生这种情况时队列始终为空,因此预计会阻塞get。我不明白为什么工作人员会阻塞put,因为队列显然没有满(它是空的!)。我尝试了blocktimeout 关键字参数,但得到了相同的结果。

我正在使用多处理反向端口,因为我坚持使用 Python 2.5。


编辑:看起来我也遇到了多处理模块提供的示例之一的死锁问题。这是倒数第三个例子here. 死锁似乎只有在我多次调用测试方法时才会发生。例如,将脚本底部更改为:


if __name__ == '__main__':
    freeze_support()
    for x in xrange(1000):
        test()

编辑:我知道这是一个老问题,但测试表明这在使用 Python 2.7 的 Windows 上不再是问题。我将尝试 Linux 并报告。

【问题讨论】:

    标签: python concurrency queue deadlock multiprocessing


    【解决方案1】:

    这个问题随着 Python 的较新版本消失了,所以我假设它是 backport 的问题。无论如何,这不再是问题。

    【讨论】:

      【解决方案2】:

      我认为问题在于父线程加入了它已通过队列的子线程。这在多处理模块的programming guidelines section 中进行了讨论。

      无论如何,我遇到了您描述的相同症状,并且当我重构我的逻辑以使主线程不加入子线程时,没有死锁。我重构的逻辑涉及知道我应该从结果或“完成”队列中获得的项目数量(可以根据子线程的数量或工作队列上的项目数量等进行预测),以及循环无限地收集所有这些。

      “玩具”逻辑图解:

      num_items_expected = figure_it_out(work_queue, num_threads)
      items_received = []
      while len(items_received) < num_items_expected:
          items_received.append(done_queue.get())
          time.sleep(5)
      

      上述逻辑避免了父线程加入子线程的需要,但允许父线程阻塞,直到所有子线程都完成。这种方法避免了我的死锁问题。

      【讨论】:

      • 我认为当进程加入时所有队列都应该是空的,所以这应该不是问题。另外,主进程在 put 上死锁,而不是 join。我刚刚升级了 Python(我被旧版本卡住了),所以我会再次测试一下。
      • @ajduff 在我的情况下,连接没有发生死锁,但 put 也发生了,除了 put 在子线程中。此外,就我而言,被放入的队列是空的。所以我认为在你的情况下也值得一试(即避免主线程加入子线程)。
      猜你喜欢
      • 1970-01-01
      • 2020-03-30
      • 2014-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多