ProcessPoolExecutor не может выполнять мои собственные функции, но выполняет печать

Код:

if __name__ == "__main__":
    p = ProcessPoolExecutor()
    p.submit(lambda x: print(x), "something")  # doesn't work
    p.submit(print, "something")  # works fine
    time.sleep(0.5)

Почему это имеет смысл?

9X_pythonista

4
0
2
Общее количество ответов: 2

Ответ #1

Ответ на вопрос: ProcessPoolExecutor не может выполнять мои собственные функции, но выполняет печать

ProcessPoolExecutor хочет замариновать функцию, но поскольку 9X_pythonic лямбда не имеет имени, ее нельзя найти для 9X_pythonista замаринования.

Например:

from pickle import dumps

def fun(x):
    print(x)

lmb = lambda x: print(x)

dumps(fun)  # succeeds
dumps(lmb)  # fails

Итак, это будет работать 9X_python-multiprocessing нормально:

import time
from concurrent.futures import ThreadPoolExecutor


def fun(x):
    print(x)


if __name__ == "__main__":
    p = ThreadPoolExecutor()
    lmb = lambda x: print(x)
    p.submit(lmb, "lambda")  # works fine
    p.submit(fun, "local function")  # works fine
    p.submit(print, "built-in function")  # works fine
    time.sleep(0.5)

Но если вы замените ThreadPoolExecutor() на ProcessPoolExecutor(), который 9X_python должен будет замариновать функцию, лямбда 9X_pythonista перестанет работать.

from concurrent.futures import ProcessPoolExecutor


if __name__ == "__main__":
    p = ProcessPoolExecutor()
    lmb = lambda x: print(x)
    future = p.submit(lmb, "lambda")  # doesn't work
    print(future.result())

Это показывает, что 9X_python проблема действительно возникает при травлении, а 9X_pythonista также объясняет, почему:

_pickle.PicklingError: Can't pickle  at 0x00000294E66B3E20>: attribute lookup  on __main__ failed

__main__ — это основной 9X_pythonic процесс, в пространстве имен которого нет 9X_py лямбды, потому что сама лямбда безымянна. Присвоение 9X_py его переменной типа lmb не меняет этого, поскольку 9X_python-multiprocessing лямбда разыменовывается из переменной. Две 9X_pythonista другие функции по своей сути имеют имена 9X_py в пространстве имен __main__ и могут быть замаринованы.

Обратите 9X_python-interpreter внимание, что __main__ — это то же имя, которое 9X_python вы бы проверили в:

if __name__ == "__main__":

10
0

Ответ #2

Ответ на вопрос: ProcessPoolExecutor не может выполнять мои собственные функции, но выполняет печать

Если вы проверите result будущего, вы увидите 9X_py соответствующее сообщение об ошибке:

>>> from concurrent.futures import ProcessPoolExecutor
>>> p = ProcessPoolExecutor()
>>> p.submit(lambda x: print(x), "something").result()
...
PicklingError: Can't pickle  at 0x113eec5e0>: attribute lookup  on __main__ failed

Таким 9X_py образом, это сообщение об ошибке говорит 9X_pythonista само за себя, если вы знакомы с тем, как 9X_python-multiprocessing работает исполнитель пула процессов. Но 9X_python-multiprocessing если это не так, то может потребоваться 9X_python-multiprocessing дополнительное объяснение: процесс попытается 9X_python получить доступ к рабочей функции по имени, но, поскольку 9X_pythonic лямбда-функции являются "анонимными" функциями, у 9X_python-interpreter них нет допустимого имени для поиска в модуле. пространство 9X_python-interpreter имен.

>>> (lambda x: print(x)).__name__
''

В качестве обходного пути вы можете 9X_pythonista использовать многопроцессорный пул pathos, который 9X_pythonic использует dill, более мощную библиотеку сериализации, чем 9X_python-interpreter pickle. В отличие от pickle, укроп может сериализовать 9X_python-shell лямбда-выражения. Пафосный интерфейс ProcessPool немного 9X_python-interpreter отличается от многопроцессорной обработки 9X_py stdlib ProcessPoolExecutor, но ближайшей аналогией с вашим 9X_python-interpreter простым использованием submit будет pipe:

>>> from pathos.multiprocessing import ProcessPool
>>> p = ProcessPool()
>>> p.pipe(lambda x: print(x), "something")
something

Если вам 9X_python-interpreter интересно, как укроп может сбрасывать лямбды, включите 9X_pythonic трассировку и посмотрите, что он на самом 9X_py деле делает с помощью этого фрагмента:

import dill.detect
dill.detect.trace(True)
dill.dumps(lambda x: print(x))

3
0