我正在尝试使用多处理来执行多个后台作业,并使用主进程作为用户界面,通过input()
接受命令。每个进程都必须执行某些作业,并将其当前状态写入字典,该字典是使用manager.dict()
创建的,然后传递给进程。
创建进程后,有一个带input()
的循环用于访问用户命令。为简单起见,这些命令减少到最低限度。
from multiprocessing import Manager
from multiprocessing import Process
with Manager() as manager:
producers = []
settings = [{'name':'test'}]
for setting in settings:
status = manager.dict()
logger.info("Start Producer {0}".format(setting['name']))
producer = Process(target=start_producer, args=(setting, status))
producer.start()
producers.append([producer, status])
logger.info("initialized {0} producers".format(len(producers)))
while True:
text_command = input('Enter your command:')
if text_command == 'exit':
logger.info("waiting for producers")
for p in producers:
p[0].join()
logger.info("Exit application.")
break
elif text_command == 'status':
for p in producers:
if 'name' in p[1] and 'status' in p[1]:
print('{0}:{1}'.format(p[1]['name'], p[1]['status']))
else:
print("Unknown command.")
在其他过程中运行的方法非常简单:
def start_producer(producer_setting: dict, status_dict: dict):
importer = MyProducer(producer_setting)
importer.set_status_dict(status_dict)
importer.run()
我创建一个MyProducer实例并通过对象的setter设置status-dictionary并调用阻塞run()
方法,该方法仅在生产者完成时返回。在致电set_status_dict(status_dict)
时,字典中会填充name
和status
元素。
当我运行代码时,生产者似乎被创建,我收到“Start Producer test”和“initialized 1 producer”输出,之后是input()
的“输入你的命令”请求,但是似乎实际过程没有运行。
当我按Enter跳过第一次循环迭代时,我得到预期的“未知命令”日志,生产者进程开始实际工作。之后,我的“状态”命令也按预期工作。
当我在第一次循环迭代中输入'status'时,我得到一个键 - 错误,因为'name'和'status'没有在字典中设置。这些密钥应在set_status_dict()
中设置,Process(target=...)
本身在start_producer
中调用。
为什么? producer.start()不应该在新进程中运行input()
的完整块,因此永远不会挂在主进程的input()
上吗?
如何在没有任何用户输入的情况下首先启动流程,然后等待sleep(1)
?
修改:有关此问题的完整mvce程序可在此处找到:https://pastebin.com/k8xvhLhn
编辑:找到初始化进程后start_producer()
的解决方案。但为什么这种行为首先发生?不应该在新进程中运行--start-maximized
中的所有代码吗?
答案 0 :(得分:1)
我对多处理模块的经验有限,但我能够让它按照你想要的方式行事(我认为)。首先,我在while循环的顶部添加了一些print语句,以查看可能发生的情况,并发现如果进程为run
或join
,则表明它有效。我认为你不希望它阻止,所以我添加了调用以进一步运行该过程 - 但似乎run()
也阻止了。事实证明,当第一次while循环迭代出现时,该过程还没有完成 - 在循环顶部添加time.sleep(30)
使得进程有足够的时间来调度(由OS)并运行。 (在我的机器上,实际上只需要200到300毫秒的午睡时间)
我将start_producer
替换为:
def start_producer(producer_setting: dict, status_dict: dict):
## importer = MyProducer(producer_setting)
## importer.set_status_dict(status_dict)
## importer.run()
#time.sleep(30)
status_dict['name'] = 'foo'
status_dict['status'] = 'thinking'
您的代码已修改:
if __name__ == '__main__':
with Manager() as manager:
producers = []
settings = [{'name':'test'}]
for setting in settings:
status = manager.dict()
logger.info("Start Producer {0}".format(setting['name']))
producer = Process(target=start_producer, args=(setting, status))
producer.start()
# add a call to run() but it blocks
#producer.run()
producers.append([producer, status])
logger.info("initialized {0} producers".format(len(producers)))
while True:
time.sleep(30)
for p, s in producers:
#p.join()
#p.run()
print(f'name:{p.name}|alive:{p.is_alive()}|{s}')
if 'name' in s and 'status' in s:
print('{0}:{1}'.format(s['name'], s['status']))
text_command = input('Enter your command:')
if text_command == 'exit':
logger.info("waiting for producers")
for p in producers:
p[0].join()
logger.info("Exit application.")
break
elif text_command == 'status':
for p in producers:
if 'name' in p[1] and 'status' in p[1]:
print('{0}:{1}'.format(p[1]['name'], p[1]['status']))
else:
print("Unknown command.")