我订阅了实时数据馈送,并根据收到的数据维护状态。通常,所有数据都是按顺序接收的,但是在丢弃消息的情况下,我对消息进行缓冲,通过REST API接收状态的快照,然后播放缓冲区,跳过在ID之前带有ID的任何消息快照中指定的一项。目前,我正在执行以下操作:
class StateManager
{
private long _lastId;
private bool _isSyncing;
private object _syncLock;
private Dictionary<decimal,decimal> _state;
private ConcurrentQueue<SocketMessage> _messageBuffer;
private ManualResetEvent _messageEvent;
private ManualResetEvent _processingEvent;
public StateManager( DataSocket socket )
{
_isSyncing = false;
_syncLock = new object();
_state = new Dictionary<decimal,decimal>();
_messageBuffer = new ConcurrentQueue<SocketMessage>();
socket.OnMessage += OnSocketMessage;
Task.Factory.StartNew( MessageProcessingThread, TaskCreationOptions.LongRunning );
}
public void ApplySnapshot( Snapshot snapshot )
{
lock( _syncLock )
{
if( _isSyncing ) return;
_isSyncing = true;
_processingEvent.Reset();
}
// Apply the snapshot to the state...
_isSyncing = false;
_processingEvent.Set();
}
private void OnSocketMessage( object sender, SocketMessage msg )
{
_messageBuffer.Enqueue( msg );
_messageEvent.Set();
}
private async Task MessageProcessingThread()
{
while(true)
{
_messageEvent.WaitOne();
while(true)
{
_processingEvent.WaitOne();
if( !_messageBuffer.TryDequeue( out var msg ) )
{
_messageEvent.Reset();
break;
}
ApplyToState( msg );
}
}
}
}
这很好用,但是我觉得它有点草率,在重负载下可能会表现更好。因此,我正在考虑过渡到Microsoft.Tpl.Dataflow
,它将为我处理排队和处理执行。但是,我以前使用过Dataflow,但我担心:
是否可以暂停ActionBlock
的执行,以便它可以缓冲新任务,但直到恢复后才处理这些新任务? ,我需要能够暂停处理,直到应用了新的快照,然后恢复并处理所有缓冲的消息。
我可以只在_processingEvent
内使用ActionBlock
,但是我觉得这会引起很多问题。首先,它将阻止任务,导致启动更多任务,而那些将阻止,迅速填满TPL的内部任务队列。此外,这将导致所有被阻止的任务同时完成,可能会出现故障,从而导致另一个重新同步事件的发生。
如果TPL无法做到这一点,那么还有更好的方法吗?