[英]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.