我正在玩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更新并更改暴露状态)。 / p>
我可以通过尝试维护一堆想要首先更新的节点来更新,但接下来需要更新他们的邻居,然后他们的邻居等等,这意味着每个更新周期我需要仔细地走图并确定正确的更新顺序,这可能会非常慢......
天真的异步方式是让每个节点都在自己的线程中(或者更简单地说,初始异步方法调用发生在每个节点的更新方法中,它会在一段时间内无限更新(true){...})。他的问题是拥有数千个线程似乎不是一个好主意!
这似乎应该有一个简单的解决方案;这与细胞自动机没有什么不同,但是我提出的任何同步解决方案要么需要更新很多次才能获得从一端到另一端的消息的节点数,或者解决某种复杂的问题。具有多个起点的图形行走问题。
异步方法似乎很简单,只要我能拥有数千个线程......
那么做这样的事情最好的方法是什么?
答案 0 :(得分:1)
我认为Rx(The Reactive Extensions)将是一个很好的起点。
其他节点可能需要依赖的每个状态都显示为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
答案 1 :(得分:0)
首先,您需要确保您的更新收敛。这与您如何执行它们(同步,异步,串行或并行)无关。
假设您有两个节点A和B,即连接。一个改变,触发B. B的重新计算然后改变,触发重新计算A.如果重新计算A改变A的值,它将触发重新计算B等等。您需要这一系列触发器在某一点停止 - 您需要更改以收敛。如果他们不这样做,你使用的技术就无法修复它。
一旦你确定计算收敛并且你没有进行无休止的重新计算,你应该从简单的单线程同步计算开始,看看它是否表现良好。如果它足够快,请停在那里。如果没有,您可以尝试并行化它。
我不会为每次计算创建一个线程,它根本不会扩展。而是使用需要执行的计算队列,并且每次更改节点A 的值时,将其所有邻居放入队列中。您可以使用几个线程来处理队列,从而使其成为一个更具可伸缩性的架构。
如果此仍然不够快,则需要优化您在队列中放置的内容以及处理方式。我认为现在担心这件事还为时过早。