我正在编写一个Python包,它从配置文件中读取模块列表(以及辅助数据)。
然后我想遍历每个动态加载的模块并在其中调用do_work()函数,该函数将生成一个新进程,以便代码在一个单独的进程中运行ASYNCHRONOUSLY。
目前,我正在我的主脚本开头导入所有已知模块的列表 - 这是一个令人讨厌的黑客,我觉得,并且不是很灵活,也是一种维护痛苦。
这是产生进程的函数。我想修改它以在遇到模块时动态加载模块。字典中的键是包含代码的模块的名称:
def do_work(work_info):
for (worker, dataset) in work_info.items():
#import the module defined by variable worker here...
# [Edit] NOT using threads anymore, want to spawn processes asynchronously here...
#t = threading.Thread(target=worker.do_work, args=[dataset])
# I'll NOT dameonize since spawned children need to clean up on shutdown
# Since the threads will be holding resources
#t.daemon = True
#t.start()
问题1
当我在脚本中调用该函数时(如上所述),我收到以下错误:
AttributeError:'str'对象没有 属性'do_work'
这是有道理的,因为字典键是一个字符串(要导入的模块的名称)。
当我添加声明时:
导入工作人员
在产生线程之前,我收到错误:
ImportError:没有名为worker
的模块
这很奇怪,因为变量名而不是它所持有的值正在被使用 - 当我打印变量时,我得到的值(正如我预期的那样)是怎么回事?
问题2
正如我在评论部分中提到的,我意识到在生成的子代中编写的do_work()函数需要在自身之后进行清理。我的理解是编写一个clean_up函数,该函数在do_work()成功完成时调用,或者捕获到未处理的异常 - 是否还需要做些什么来确保资源不泄漏或使操作系统处于不稳定状态?
问题3
如果我注释掉t.daemon标志语句,代码stil会运行ASYNCHRONOUSLY吗?由产生的孩子们开展的工作相当密集,我不想在产生另一个孩子之前等待一个孩子完成。顺便说一句,我知道Python中的线程实际上是一种时间共享/切片 - 没关系
最后是否有更好的(更多Pythonic)方式来做我想做的事情?
[编辑]
在Python中阅读了更多关于Pythons GIL和线程(ahem-hack)之后,我认为最好使用单独的进程(至少IIUC,如果脚本可用,脚本可以利用多个进程),所以我将产生新的流程而不是线程。
我有一些产生进程的示例代码,但它有点简单(使用lambad函数)。我想知道如何扩展它,以便它可以处理已加载模块中的运行函数(就像我上面所做的那样)。
这是我所拥有的片段:
def do_mp_bench():
q = mp.Queue() # Not only thread safe, but "process safe"
p1 = mp.Process(target=lambda: q.put(sum(range(10000000))))
p2 = mp.Process(target=lambda: q.put(sum(range(10000000))))
p1.start()
p2.start()
r1 = q.get()
r2 = q.get()
return r1 + r2
我如何修改它来处理模块字典并在新进程中的每个已加载模块中运行do_work()函数?
答案 0 :(得分:2)
答案 1 :(得分:1)
此修订是为了在此处使用 import ()文档:import并重构以利用此处记录的请求的多处理模块:multiprocessing。这尚未经过测试。
def do_work(work_info):
q = mp.Queue()
for (worker, dataset) in work_info.items():
xworker = __import__(worker)
p = mp.Process(target=xworker.do_work, args=dataset).start()
q.put(p)
while not q.empty():
r = q.get()