我正在设计一个大型项目,我想我看到了一种可以通过利用多核来大大提高性能的方法。但是,我对多处理的经验为零,我有点担心我的想法可能不是好主意。
想法
该程序是一种视频游戏,可程序生成大量内容。由于一次生成的内容太多了,因此该程序会尝试在需要之前或仅在需要之前生成所需的内容,并花费大量的精力来尝试预测不久的将来以及在不久的将来需要什么 future 是。因此,整个程序围绕一个任务调度程序构建,该任务调度程序通过传递的函数对象以及附加的元数据位来帮助确定应按什么顺序处理它们并按该顺序调用它们。
动机
使这些函数在自己的进程中同时执行似乎应该很容易。但是查看多处理模块的文档会让我重新考虑-似乎没有任何简单的方法可以在线程之间共享大型数据结构。我忍不住想像这是故意的。
问题
因此,我想我需要知道答案的基本问题是:
对不起,我很天真,但是我没有接受过正式的计算机科学教育(至少现在还没有),而且我以前从未使用过并发系统。我要在此处实现的想法甚至是远程可行的,还是任何允许我透明地同时执行任意函数的解决方案会导致如此多的开销,以至于最好在一个线程中完成所有操作?
示例
为了最大程度的清晰起见,下面是一个我想象系统如何工作的示例:
播放器已指示UI模块将 View 移到特定的空间区域。它将此通知给内容管理模块,并要求它确保玩家当前可以单击的所有星星都已完全生成并且可以被单击。
内容管理模块检查并发现UI表示玩家可能尝试与之交互的几个星星,实际上还没有产生单击时会显示的详细信息。它会产生许多Task对象,其中包含这些恒星的方法,这些恒星的方法在被调用时将生成必要的数据。它还向这些任务对象添加了一些元数据,假设(可能基于从UI模块收集的更多信息)假设玩家尝试单击任何内容之前0.1秒,并且图标最接近光标的星星具有最大的被点击的机会,因此应要求它比距离光标更远的星星稍早一些。然后,将这些对象添加到调度程序队列中。
调度程序根据需要完成每个任务的时间来快速对其队列进行排序,然后将第一个任务对象从队列中弹出,从其包含的功能中创建一个新进程,然后不再考虑该进程,而只是弹出另一个任务离开队列并将其填充到一个进程中,然后是下一个,然后是下一个...
同时,新过程执行,将它生成的数据存储在作为方法的星形对象上,并在到达
return
语句时终止。
然后,UI会注册玩家现在确实点击了星标,并查找需要显示在已点击代表 Sprite 的星标对象上的数据。如果数据在那里,它将显示它;否则,它将显示它。如果不是,则UI会显示一条消息,要求玩家等待,然后继续反复尝试访问星形对象的必要属性,直到成功为止。
请您参考如下方法:
即使您的问题看起来很复杂,也有一个非常简单的解决方案。您可以使用代理隐藏所有复杂的跨进程共享对象的内容。
基本思想是创建一个管理器,该管理器管理应在流程之间共享的所有对象。然后,该管理器创建自己的进程,在该进程中等待其他进程指示它更改对象。但是足够说了。看起来像这样:
import multiprocessing as m
manager = m.Manager()
starsdict = manager.dict()
process = Process(target=yourfunction, args=(starsdict,))
process.run()
存储在
starsdict
中的对象不是真正的
dict
。相反,它会将您所做的所有更改和请求发送给其经理。这称为“代理”,它与它模仿的对象具有几乎完全相同的API。这些代理是可腌制的,因此您可以将其作为参数传递给新进程中的函数(如上图所示)或通过队列发送它们。
您可以在 documentation中阅读有关此内容的更多信息。
我不知道如果两个进程同时访问它们,代理将如何 react 。由于它们是为并行而设计的,所以我猜它们应该是安全的,即使我听说不是。最好是自己进行测试或在文档中查找。