在Python程序中设计并发性



我正在设计一个大型项目,我想我看到了一种可以通过利用多个核心来大幅提高性能的方法。然而,我对多处理没有任何经验,我有点担心我的想法可能不太好。

想法

该程序是一款视频游戏,按程序生成大量内容。由于一次生成的内容太多了,因此程序会尝试在需要之前生成所需内容,并花费大量精力来预测在不久的将来需要什么以及距离多远。因此,整个程序都是围绕任务调度器构建的,它获取附加了元数据位的传递函数对象,以帮助确定它们应该按什么顺序处理,并按该顺序调用它们。

动机

让这些函数在自己的进程中同时执行似乎应该很容易。但是,查看多处理模块的文档让我重新考虑——似乎没有任何简单的方法可以在线程之间共享大型数据结构。我忍不住想这是故意的。

问题

所以我想我需要知道答案的基本问题是:

  1. 有什么实用的方法可以允许多个线程访问同一列表/dict/等吗。。。同时阅读和写作?我可以启动我的星生成器的多个实例,让它访问包含所有星的dict,并从其他线程的角度让新对象出现在dict中吗(也就是说,我不必从生成星的过程中明确地获取星;我只需要把它从dict中拉出,就好像主线程自己把它放在那里一样)。

  2. 如果没有,是否有任何实用的方法可以允许多个线程同时读取相同的数据结构,但将其结果数据反馈给主线程,以便安全地滚动到同一数据结构中?

  3. 即使我确保没有两个并发函数试图同时访问相同的数据结构,无论是用于读取还是写入,这种设计是否有效?

  4. 数据结构是否可以在进程之间固有地共享,或者我是否总是明确地必须将数据从一个进程发送到另一个进程,就像我通过TCP流通信的进程一样?我知道有些物体会抽象掉这类东西,但我在问是否可以完全去掉它;让每个线程正在查看的对象实际上是同一个内存块。

  5. 模块提供的对象在抽象过程之间的通信方面有多灵活?我是否可以将它们作为现有代码中使用的数据结构的替代品,而不注意到任何差异?如果我做这样的事情,会不会造成难以控制的开销?

很抱歉我太天真了,但我没有受过正式的计算机科学教育(至少还没有),而且我以前从未使用过并发系统。我试图在这里实现的想法是否非常实用,或者任何允许我透明地同时执行任意函数的解决方案是否会造成如此大的开销,以至于我最好在一个线程中完成所有工作?

示例

为了获得最大的清晰度,这里有一个我认为该系统如何工作的例子:

玩家已指示UI模块将视图移动到某个空间区域。它通知内容管理模块这一点,并要求其确保玩家当前可以点击的所有明星都已完全生成并准备好点击

内容管理模块检查并发现,UI所说的玩家可能尝试与之互动的几位明星实际上还没有生成点击时显示的详细信息。它生成了许多包含这些恒星方法的Task对象,这些方法在被调用时将生成必要的数据。它还向这些任务对象添加了一些元数据,假设(可能基于从UI模块收集的进一步信息)玩家尝试点击任何东西之前需要0.1秒,并且图标离光标最近的星星被点击的机会最大,因此应该比离光标更远的星星更早请求一段时间。然后,它将这些对象添加到调度程序队列中。

调度器根据每个任务需要完成的时间快速对队列进行排序,然后从队列中弹出第一个任务对象,从它包含的函数中创建一个新进程,然后不再考虑该进程,而是从队列中取出另一个任务,并将其也塞进一个进程中,然后是下一个,再下一个。。。

同时,新进程执行,将生成的数据存储在它所属的星形对象上,并在到达return语句时终止。

然后,UI注册玩家现在确实点击了一颗星星,并查找它需要在其代表性精灵被点击的星星对象上显示的数据。如果数据在那里,它就会显示它;如果没有,UI会显示一条消息,要求玩家等待,并继续反复尝试访问星形对象的必要属性,直到成功为止。

即使您的问题看起来非常复杂,也有一个非常简单的解决方案。您可以使用代理隐藏跨进程共享对象的所有复杂内容。

基本思想是创建一些管理器来管理应该在流程之间共享的所有对象。然后,这个管理器创建自己的进程,等待其他进程指示它更改对象。但说得够多了。它看起来像这样:

import multiprocessing as m
manager = m.Manager()
starsdict = manager.dict()
process = Process(target=yourfunction, args=(starsdict,))
process.run()

存储在starsdict中的对象不是真正的dict。相反,它将所有更改和请求发送给它的管理器。这被称为"代理",它与它所模仿的对象几乎完全相同的API。这些代理是可拾取的,因此您可以将其作为参数传递给新进程中的函数(如上图所示)或通过队列发送它们。

您可以在文档中阅读更多相关内容。

我不知道如果两个进程同时访问代理,代理会有什么反应。既然它们是为并行而设计的,我想它们应该是安全的,尽管我听说它们不是。最好是您自己测试或在文档中查找它。

相关内容

  • 没有找到相关文章

最新更新