异步更新图形
本文关键字:图形 更新 异步 | 更新日期: 2023-09-27 18:33:56
我正在玩弄 C# 中的一个想法,并希望就异步更新图形中大量节点的最佳方法提供一些建议。我还没有读过任何关于如何做这样的事情,我在教科书/示例中看到的所有内容都使用其节点实际上没有变化的图形。
假设我有一个包含大量节点(数千个(的图表。每个节点都有一些内部状态,该状态取决于其每个邻居的一些公共属性,以及潜在的一些外部输入。
所以从示意性上讲,节点很简单:
class Node
{
State internalState;
public State exposedState;
Input input;
List<Node> neigbors;
void Update()
{
while (true)
{
DoCalculations(input, internalState, neighbors);
exposedState = ExposedState(internalState);
}
}
State ExposedState(State state) { ... }
void DoCalculations() { ... }
}
困难在于我希望节点的输入状态发生变化(通过订阅事件或轮询(或邻居的状态发生变化时立即更新。如果我尝试以天真的方式同步执行此操作,我会遇到明显的问题:
Node A updates when input changes
Its neighbor B sees A has changed, updates.
Node A sees its neighbor B has changed, updates
B updates
A updates
....
Stack overflows
如果我通过枚举所有节点并调用它们的更新方法进行更新,则节点可能会不一致地更新(例如:A 的输入更改,B 更新并且看不到 A 的更改,A 更新和更改暴露状态(。
我可以通过尝试维护一堆想要首先更新的节点来更新,但随后他们的邻居需要更新,他们的邻居需要下一个更新,依此类推,这意味着每个更新周期我都需要仔细浏览图形并确定正确的更新顺序,这可能非常慢......
朴素的异步方法是将每个节点放在自己的线程中(或者更简单地说,初始异步方法调用发生在每个节点的更新方法上,该方法在一段时间内无限期更新(true({...}(。他的问题是拥有数千个线程似乎不是一个好主意!
看起来这应该有一个简单的解决方案;这与元胞自动机没有太大区别,但是我想出的任何同步解决方案都必须与节点数量相比进行大量更新才能将消息从一端传递到另一端,或者解决某种复杂的图形行走问题与多个起点。
异步方法似乎很简单,如果我能有数千个线程......
那么做这样的事情最好的方法是什么?
我认为Rx(反应式扩展(将是一个很好的起点。
其他节点可能需要依赖的每个状态都作为IObserable<TState>
公开,然后其他节点可以订阅这些可观察量:
otherNode.PieceOfState.SubScribe(v => { UpdateMyState(v) });
Rx 为可观察量提供了许多过滤和处理功能:这些函数可用于过滤重复事件(但当然,您需要定义"重复"(。
这是一篇介绍性文章:http://weblogs.asp.net/podwysocki/archive/2009/10/14/introducing-the-reactive-framework-part-i.aspx
首先,您需要确保更新收敛。这与你如何执行它们(同步、异步、串行或并行(无关。
假设您有两个节点 A 和 B,它们是连接。A 更改,触发 B 的重新计算,然后更改,触发 A 的重新计算。如果 A 的重新计算改变了 A 的值,它将触发 B 的重新计算,依此类推。您需要这一系列触发器在某一点停止 - 您需要收敛更改。如果他们不这样做,您使用的任何技术都无法修复它。
一旦你确定计算收敛并且你不会陷入无休止的重新计算,你应该从简单的单线程同步计算开始,看看它是否表现良好。如果它足够快,就停在那里。如果没有,您可以尝试并行化它。
我不会为每个计算创建一个线程,它根本不可扩展。而是使用需要执行的计算队列,每次更改节点 A 的值时,将其所有邻居放入队列中。您可以让几个线程处理队列,使其成为更具可扩展性的体系结构。
如果这仍然不够快,则需要优化放入队列的内容以及处理方式。我认为现在担心还为时过早。