C# 阻塞TPL数据流处理

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

我订阅了实时数据馈送,并根据接收到的数据维护状态。正常情况下,所有数据都是按顺序接收的,但在丢弃消息的情况下,我会缓冲消息,通过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 );
      }

    }
  }
}
类状态管理器
{
私人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的性能非常好,而且更容易理解。此外,请记住为完全关闭添加取消