阻止TPL数据流处理

时间:2019-04-04 16:41:03

标签: c# task-parallel-library dataflow

我订阅了实时数据馈送,并根据收到的数据维护状态。通常,所有数据都是按顺序接收的,但是在丢弃消息的情况下,我对消息进行缓冲,通过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无法做到这一点,那么还有更好的方法吗?

0 个答案:

没有答案