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