У меня есть несколько multiprocessing.Process
ов, и я хотел бы, чтобы они потребляли (очередь get()
) вызываемые необратимые объекты и вызывали их.Они были созданы до fork()
, поэтому они не должны нуждаться в травлении.
Использование multiprocessing.Queue
не работает, поскольку оно пытается засолить все:
import multiprocessing as mp
# create non-global callable to make it unpicklable
def make_callable():
def foo():
print("running foo")
return foo
def bar():
print("running bar")
def runall(q):
while True:
c = q.get()
if c is None:
break
c()
if __name__ == '__main__':
q = mp.Queue()
call = make_callable()
p = mp.Process(target=runall, args=(q,))
p.start()
q.put(bar)
q.put(call)
q.put(None)
p.join()
running bar
Traceback (most recent call last):
File "/usr/lib64/python3.7/multiprocessing/queues.py", line 236, in _feed
obj = _ForkingPickler.dumps(obj)
File "/usr/lib64/python3.7/multiprocessing/reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'make_callable.<locals>.foo'
Эквивалентом реализации будет помещение всех объектов в глобальный (или переданный) список и передача только индексов, что работает:
import multiprocessing as mp
# create non-global callable to make it unpicklable
def make_callable():
def foo():
print("running foo")
return foo
def bar():
print("running bar")
def runall(q, everything):
while True:
c = q.get()
if c is None:
break
everything[c]()
if __name__ == '__main__':
q = mp.Queue()
call = make_callable()
everything = [bar, call]
p = mp.Process(target=runall, args=(q,everything))
p.start()
q.put(0)
q.put(1)
q.put(None)
p.join()
running bar
running foo
Проблема в том, что, хотя я знаю, что ни один из передаваемых вызовов не будетбыть сборщиком мусора (и, следовательно, их адреса останутся действительными), у меня нет полного списка заранее.
Я также знаю, что мог бы, вероятно, использовать multiprocessing.Manager
и его реализацию Queue
с использованием объекта Proxy
, но это кажется большой нагрузкой, особенно в реальной реализации, я бы также передавал другие извлекаемые данные.
Есть ли способ выбрать и передать только адресную ссылку на объект, общий для всехнесколько процессов?
Спасибо!