【发布时间】:2009-11-08 20:25:06
【问题描述】:
各位,我正在使用 C++ 开发一个多人游戏应用程序,目前正在为其选择合适的多线程架构。
应用程序的核心是无限循环,它本质上是更新游戏世界的所有实体的每一帧。目前这个世界循环是单线程的。它工作得很好,但我真的想让它在多核上更具可扩展性。
由于所有 World 实体都存在于 Locations 中并在每一帧中更新如下:
- World::update(dt) //dt 是自上一帧以来的增量时间 - 位置::更新(dt) - WorldEntity::update(dt) - WorldEntity::update(dt) - ... - 位置::更新(dt) - WorldEntity::update(dt)...我正在考虑在单独的线程中运行每个位置(及其更新逻辑)。这意味着我需要正确同步 World 实体。这是我真正不想做的事情,因为我相信,在域类方法中的显式锁定是错误的,它使开发、维护和调试变得更加困难。
起初我正在考虑通过禁止它们之间的任何调用来将位置实体与不同位置的实体隔离开来。有哪些可能的方法来实现这一目标?将每个位置的实体存储在线程本地存储中,以便无法从外部访问它们?或者也许不是每个位置的线程而是使用进程?(但这会使一切复杂化很多)。
但是,即使 Location 实体被很好地隔离,还有另一个问题 - 持久性。我已经有某种简单的通用持久性服务,它在单独的线程中运行。它可以在异步模式下使用,它接受一个要保存的对象并返回一个特殊的未来对象,该对象可用于跟踪持久性过程。我很想使用这项服务,但是由于它在单独的线程中运行,我再次需要正确同步对域类的访问。在这种情况下,可能的选择是实现域对象的正确克隆,以便持久性服务接受要保存的对象的副本,并且不需要显式锁定......
因此问题是,以上所说的一切都值得吗?或者也许我应该简单地将显式同步逻辑添加到所有域类中并完成它?或者也许有一些我不知道的更好的选择?
提前致谢
更新感谢 Jed Smith 添加了世界结构方案
【问题讨论】:
-
你能想象一下你的代码结构吗?以及各个阶段和功能之间的相互作用。最重要的是您需要在代码中找到并行性。此外,请在“世界”、“位置”等术语中使用“”。你想并行化一个大循环。如果循环没有任何“循环携带的依赖”,那么它很容易。但是,就您而言,事实并非如此。然后,可以实现“管道并行”。是的,我知道有一些流行语,你可能不熟悉。但是,这是循环级并行化的一般策略。
-
这里最好做什么?通过编辑原始帖子或回答我自己?
-
哦,谢谢,我知道了。您还需要检查“依赖项”。例如, WorldEntity::update 是否与之前的调用有依赖关系?地点呢?了解依赖关系是并行化的第一步。
-
在这种情况下实际上可以实现流水线。很难用简短的回答来解释。 en.wikipedia.org/wiki/Instruction_pipeline (1) 将每次迭代的大任务分成子任务。 (2) 并发执行子任务。然而,实施并不是那么容易。但是,这种并行化是最难的一种。
-
如果 A 依赖于 B,那么执行顺序 A -> B 应该被保留。无论如何,除了持久性问题之外,可以通过调整管道并行性来并行化这样的循环。我做了几次,效果很好(四核加速 2~3 倍)。流水线并行的概念与指令流水线完全相同(参见上面的 Wiki 链接)。
标签: c++ multithreading locking