簡體   English   中英

在C#中從Feeder接收大量tcp套接字財務數據的最佳方法?

[英]Best way to receive high volume tcp socket financial data from a feeder in c#?

我正在開發C#Windows服務,它將從使用TCP的饋送器接收財務報價。 我的項目必須接收和處理大量數據,因為我將跟蹤140個用於每秒更新SQL數據庫的不同資產。

我正在使用循環從BackgroundWork線程中的套接字中收集數據:

  try
  {
    // Send START command with the assets.
    if (!AeSocket.AeSocket.Send(Encoding.ASCII.GetBytes(String.Format("{0}{1}START{1}BC|ATIVO{1}{2}{3}", GlobalData.GlobalData.Id, GlobalData.GlobalData.Tab, AeSocket.AeSocket.GetAssets(),
                                                                      GlobalData.GlobalData.Ret))).Contains("OK"))
    {
      throw new Exception("Advise was no accepted.");
    }

    // Pool the socket and send all received string to the queue for processing in the background.
    while (true)
    {
      // Make sure the connection to the socket is still active.
      if (!AeSocket.AeSocket.Client.Connected)
      {
        throw new Exception("The connection was closed.");
      }

      // If no data is available in the socket, loop and keep waiting.
      if (!AeSocket.AeSocket.Client.Poll(-1, SelectMode.SelectRead))
      {
        continue;
      }

      // There are data waiting to be read.
      var data = new Byte[AeSocket.AeSocket.ReadBufferSize];
      var bytes = AeSocket.AeSocket.Client.Receive(data, 0);
      AeSocket.AeSocket.Response = Encoding.Default.GetString(data, 0, bytes);

      // Push into the queue for further processing in a different thread.
      GlobalData.GlobalData.RxQueue.Add(AeSocket.AeSocket.Response);
    }
  }
  catch
  {
    backgroundWorkerMain.CancelAsync();
  }
  finally
  {
    AeSocket.AeSocket.Client.Close();
    AeSocket.AeSocket.Client.Dispose();
  }

接收到的數據在單獨的線程中進行處理,以避免由於接收到的大量數據而阻塞套接字接收活動。 我正在使用BlockingCollection(RxQueue)。

如以下代碼片段所示,正在觀察該集合:

  // Subscribe to the queue for string processing in another thread.
  // This is a blocking observable queue, so it is run in this background worker thread.
  GlobalData.GlobalData.Disposable = GlobalData.GlobalData.RxQueue
    .GetConsumingEnumerable()
    .ToObservable()
    .Subscribe(c =>
    {
      try
      {
        ProcessCommand(c);
      }
      catch
      {
        // Any error will stop the processing.
        backgroundWorkerMain.CancelAsync();
      }
    });

然后將數據添加到ConcurrentDictionary中,以一秒鍾的計時器異步讀取並保存到SQL數據庫中:

      // Add or update the quotation record in the dictionary.
      GlobalData.GlobalData.QuotDict.AddOrUpdate(dataArray[0], quot, (k, v) => quot);

一秒鍾的系統計時器在另一個BackgroundWorker線程中處理,並且保存從ConcurrentDictionary中讀取的報價數據。

  // Update the gridViewAssetQuotations.
  var list = new BindingList<MyAssetRecord>();

  foreach (var kv in GlobalData.GlobalData.QuotDict)
  {
    // Add the data in a database table...
  }

這是解決這種情況的好方法嗎?

使用BlockingCollection作為異步隊列並使用ConcurrentDictionary允許從另一個線程異步讀取是這樣做的好方法嗎?

那我以前從套接字中池數據的方式又如何呢:

      // If no data is available in the socket, loop and keep waiting.
      if (!AeSocket.AeSocket.Client.Poll(-1, SelectMode.SelectRead))
      {
        continue;
      }

有更好的方法嗎?

另外,我必須每4秒向TCP服務器發送一個KeepAlive命令。 我可以使用另一個系統計時器來完全異步地忽略上述池循環,還是必須將其同步到池操作? 服務器僅允許在一個端口上進行連接。

在此先感謝您的任何建議。

愛德華多·金塔納

您的循環將導致處理器使用率升高。 如果沒有要處理的數據,請放置一個睡眠(例如1 ms),如果在下一個周期中仍然沒有數據,則增加睡眠時間,如果獲得數據,則減少睡眠時間。 這樣,讀取器循環將自動適應數據流量,並節省處理器周期。 休息都很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM