C# 阻塞TPL数据流处理
我订阅了实时数据馈送,并根据接收到的数据维护状态。正常情况下,所有数据都是按顺序接收的,但在丢弃消息的情况下,我会缓冲消息,通过REST API接收状态快照,然后播放缓冲区,跳过任何Id在快照中指定的Id之前的消息。目前,我正在做以下工作:C# 阻塞TPL数据流处理,c#,task-parallel-library,dataflow,C#,Task Parallel Library,Dataflow,我订阅了实时数据馈送,并根据接收到的数据维护状态。正常情况下,所有数据都是按顺序接收的,但在丢弃消息的情况下,我会缓冲消息,通过REST API接收状态快照,然后播放缓冲区,跳过任何Id在快照中指定的Id之前的消息。目前,我正在做以下工作: class StateManager { private long _lastId; private bool _isSyncing; private object _syncLock; private Dictionary<deci
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 );
}
}
}
}
类状态管理器
{
私人long_lastId;
私人楼宇同步;
私有对象\u同步锁;
私人字典(国家),;
私有ConcurrentQueue\u消息缓冲区;
私人手册重置事件_messageEvent;
专用手册重置事件_processingEvent;
公共状态管理器(DataSocket套接字)
{
_isSyncing=false;
_syncLock=新对象();
_state=新字典();
_messageBuffer=新的ConcurrentQueue();
socket.OnMessage+=OnSocketMessage;
Task.Factory.StartNew(MessageProcessingThread,TaskCreationOptions.LongRunning);
}
public void ApplySnapshot(快照)
{
锁(同步锁)
{
如果(同步)返回;
_isSyncing=true;
_processingEvent.Reset();
}
//将快照应用于状态。。。
_isSyncing=false;
_processingEvent.Set();
}
私有void OnSocketMessage(对象发送方,SocketMessage消息)
{
_messageBuffer.Enqueue(msg);
_messageEvent.Set();
}
私有异步任务MessageProcessingThread()
{
while(true)
{
_messageEvent.WaitOne();
while(true)
{
_processingEvent.WaitOne();
if(!\u messageBuffer.TryDequeue(out var msg))
{
_messageEvent.Reset();
打破
}
ApplyToState(msg);
}
}
}
}
这工作很好,但我觉得它有点马虎,在重载下可以表现得更好。因此,我正在考虑转换到Microsoft.Tpl.Dataflow
,它将为我处理排队和处理执行。但是,我以前使用过数据流,我有一个顾虑:
是否有一种方法可以暂停执行操作块
,这样它将缓冲新任务,但在我恢复之前不会处理它们?如果我检测到丢弃的消息,我需要能够暂停处理,直到应用新的快照,然后恢复并处理所有缓冲的消息
我可以在ActionBlock
中使用\u processingEvent
,但我觉得这会导致一系列问题。首先,它会阻塞任务,导致更多任务启动,而这些任务会阻塞,很快填满TPL的内部任务队列。此外,它将导致所有被阻止的任务同时完成,可能是无序的,从而导致另一个重新同步事件发生
如果第三方物流无法做到这一点,有没有更好的方法呢?我会选择任务。使用异步GetItem方法包装队列,MessageProcessing可以等待并控制队列返回的时间,例如通过TaskCompletionSource。然后,一旦您必须刷新状态,就不要返回消息。应用新状态,丢弃旧消息并开始返回新消息。async/await的性能非常好,而且更容易理解。另外,请记住为大批量关闭添加取消,我将与任务一起执行。使用异步GetItem方法包装队列,MessageProcessing可以等待并控制队列返回的时间,例如通过TaskCompletionSource。然后,一旦您必须刷新状态,就不要返回消息。应用新状态,丢弃旧消息并开始返回新消息。async/await的性能非常好,而且更容易理解。此外,请记住为完全关闭添加取消