Тупик в коде concurrent.futures

Я пытался распараллелить некоторый код, используя concurrent.futures.ProcessPoolExecutor , но у меня продолжались странные взаимоблокировки, которых не было с ThreadPoolExecutor . Минимальный пример:

from concurrent import futures

def test():
    pass

with futures.ProcessPoolExecutor(4) as executor:
    for i in range(100):
        print('submitting {}'.format(i))
        executor.submit(test)

В python 3.2.2 (на 64-битной Ubuntu) это, кажется, постоянно зависает после отправки всех заданий - и это, кажется, происходит всякий раз, когда количество отправленных заданий превышает количество рабочих. Если я заменю ProcessPoolExecutor на ThreadPoolExecutor , он будет работать безупречно.

В качестве попытки разобраться, я дал каждому future-объекту обратный вызов, чтобы вывести значение i :

from concurrent import futures

def test():
    pass

with futures.ProcessPoolExecutor(4) as executor:
    for i in range(100):
        print('submitting {}'.format(i))
        future = executor.submit(test)

        def callback(f):
            print('callback {}'.format(i))
        future.add_done_callback(callback)

Это еще больше сбило меня с толку - напечатанное значение i by callback - это значение во время его вызова, а не во время его определения (поэтому я никогда не вижу callback 0 , но я получаю много callback 99 с). Опять же, ThreadPoolExecutor выводит ожидаемое значение.

Интересно, может ли это быть ошибкой, я попробовал последнюю версию python для разработки. Теперь код, по крайней мере, кажется завершенным, но я все равно получаю неверное значение i .

Кто-нибудь может объяснить:

  • что случилось с ProcessPoolExecutor между python 3.2 и текущей версией разработчика, которая, по-видимому, устранила этот тупик

  • , почему «неправильное» значение i печатается

РЕДАКТИРОВАТЬ: как указал ниже Юкевич, конечно, печать i напечатает значение во время вызова обратного вызова, я не знаю, о чем я думал ... если я передам вызываемый объект со значением i в качестве одного из его атрибутов, это будет работать должным образом.

РЕДАКТИРОВАТЬ: немного больше информации: выполняются все обратные вызовы, поэтому похоже, что это executor.shutdown (вызывается исполнителем .__ exit __ ), который не может сказать, что процессы завершены. Кажется, что это полностью исправлено в текущем Python 3.3, но, похоже, было много изменений в multiprocessing и concurrent.Futures , поэтому я не знаю, что это исправило. Поскольку я не могу использовать 3.3 (похоже, он несовместим ни с выпуском, ни с версией numpy для разработчиков), я попытался просто скопировать его многопроцессорные и параллельные пакеты в свою установку 3.2, которая, похоже, работает нормально. Тем не менее, кажется немного странным, что - насколько я могу судить - ProcessPoolExecutor полностью не работает в последней версии выпуска, но это не касается других.

6
задан dano 24 July 2014 в 15:00
поделиться