我知道一般来说,对象不应该在多进程之间共享,以及由此产生的问题。但我的要求是必须这样做。在
我有一个复杂的对象,里面有很多异步的协同进程。 在一个单独的进程中对这个对象运行一个长时间运行的进程的函数。现在,我想在主进程中运行ipythonshell,并在这个复杂对象上操作,而这个长时间运行的进程正在另一个进程中运行。在
为了跨进程共享这个复杂的对象,我尝试了多处理BaseManager方法,我遇到了这样的方法:
import multiprocessing
import multiprocessing.managers as m
class MyManager(m.BaseManager):
pass
MyManager.register('complex_asynio_based_class', complex_asynio_based_class)
manager = MyManager()
manager.start()
c = manager.complex_asynio_based_class()
process = multiprocessing.Process(
target=long_running_process,
args=(c,),
)
但这会产生错误:
^{pr2}$它不工作,因为对象中有协同程序。我想不出一个更好的解决方案来让它发挥作用,我只能坚持下去。在
若不是Python,我会为长时间运行的进程生成一个线程,并且仍然能够对其进行操作。在
如果我没说错的话,这应该是多进程应用程序运行后台进程和只对其执行只读操作的主进程的常见模式,就像我的例子一样,而不是修改它。我想知道一般是怎么做的?在
无法拾取的复杂对象如何在多进程之间共享?
我使用多处理模块和异步模块有一段时间了。在
进程之间不共享对象。在一个进程中创建一个对象(referent),返回一个代理对象并与另一个进程共享。另一个进程使用代理对象来调用referent的方法。在
在您的代码中,referent是基于复杂的\u asynio_类实例。在
这是你可以参考的愚蠢代码。主线程是一个运行UDP服务器和其他异步操作服务器的异步循环。长时间运行的进程简单地检查循环状态。在
无法在进程之间自动共享正在运行的协程,因为协程在拥有异步类的进程中的特定事件循环中运行。协同例程的状态不能被pickle,即使可以,它在事件循环的上下文之外也没有意义。在
您可以为您的异步类创建一个基于回调的适配器,每个协程方法都由一个基于回调的方法表示,该方法的语义是“开始做X,完成后调用这个函数”。如果回调是支持多处理的,则可以从其他进程调用这些操作。然后,您可以在每个进程中启动一个事件循环,并在基于代理的回调调用上创建一个协程facade。在
例如,考虑一个普通的异步类:
基于回调的适配器可以使用公共的
^{pr2}$asyncio
API将repeat
协同例程转换为JavaScript“callback hell”样式的经典异步函数:(转换可以自动进行,上面手动编写的代码只是展示了概念。)
CallbackAdapter
可以注册为多处理,因此不同的进程可以通过多处理提供的代理来启动适配器的方法(因此也可以启动原始的异步协同程序)。这只要求作为on_success
传递的回调是多处理友好的。在最后一步,我们可以绕一圈,为基于回调的API()创建一个异步适配器,同时在另一个进程中启动一个事件循环,并使用asyncio和
async def
。适配器类的适配器将运行一个功能齐全的repeat
协程,该协程有效地代理原始的Async.repeat
协程,而不必尝试pickle协程状态。在以下是上述方法的示例实现:
代码在python3.5上正确运行,但在3.6和3.7上由于a bug in multiprocessing而失败。在
相关问题 更多 >
编程相关推荐