Проблема
Я пишу программный продукт, в котором я хотел бы поделиться объектом из определенного модуля.Этот объект должен быть модифицируемым из разных модулей и внутри разных процессов.Рассмотрим следующую (упрощенную) версию проблемы:
Модули
module_shared.py
# Example class with simplified behaviour
class Shared:
def __init__(self):
self.shared = dict()
def set(self, **kwargs):
for key, value in kwargs.items():
self.shared[key] = value
def get(self, *args):
return {key: self.shared[key] for key in args} if args else self.shared
# Module-scope instance of the Shared class
shared = Shared()
module_a.py
from multiprocessing import Process
from time import sleep
import module_shared as ms
def run():
Process(target=run_process).start()
def run_process():
i = 0
while True:
sleep(3)
ms.shared.set(module_a=i)
i+=1
print("Shared from within module_a", ms.shared.get())
module_b.py
from multiprocessing import Process
from time import sleep
import module_shared as ms
def run():
Process(target=run_process).start()
def run_process():
i = 0
while True:
sleep(2)
ms.shared.set(module_b=i)
i-=1
print("Shared from within module_b", ms.shared.get())
module_main.py
import module_a
import module_b
import module_shared as ms
from time import sleep
if __name__ == '__main__':
module_a.run()
module_b.run()
while True:
sleep(5)
print("Shared from within module_main", ms.shared.get())
Выход
Результат работы module_main
выглядит следующим образом:
Shared from within module_b {'module_b': 0}
Shared from within module_a {'module_a': 0}
Shared from within module_b {'module_b': -1}
Shared from within module_main {}
Shared from within module_a {'module_a': 1}
Shared from within module_b {'module_b': -2}
...
Ожидаемый результат выглядит следующим образом:
Shared from within module_b {'module_b': 0}
Shared from within module_a {'module_a': 0, 'module_b': 0}
Shared from within module_b {'module_a': 0, 'module_b': -1}
Shared from within module_main {'module_a': 0, 'module_b': -1}
Shared from within module_a {'module_a': 1, 'module_b': -1}
Shared from within module_b {'module_a': 1, 'module_b': -2}
...
Дальнейшее объяснение
Экземпляр shared
не изменяется глобально, потому что каждый процесс имеет свое собственное пространство памяти.Первоначально я попытался исправить это с помощью модуля Manager
из multiprocessing
, однако мне не удалось его настроить, я полагаю, из-за ошибок, связанных с тем, когда и как выполняются операторы импорта.Вот сообщение об ошибке при вызове Manager()
в Shared
__init__
:
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
На данный момент лучшим решением было использование потоков, однако я бы предпочел вместо этого использовать процессы.Естественно, если существуют более простые (или лучшие) решения, я был бы очень рад их рассмотреть.
EDIT :
Я понял, что сделал опечатку вМоя предыдущая попытка с многопоточностью и использованием нескольких потоков на самом деле работает отлично.Отличный урок, чтобы научиться читать код дважды ...