Python multiprocessing.Queue在put和get上死锁

时间:2010-06-25 21:39:30

标签: python concurrency queue deadlock multiprocessing

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


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并报告回来。

2 个答案:

答案 0 :(得分:4)

我认为问题是父线程加入了一个传递了Queue的子线程。这将在多处理模块的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)

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

答案 1 :(得分:0)

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