我正在编写外汇交易机器人,我使用BlockingCollection在一段时间(大约2小时)后运行outOfMemory异常。 我基本上有一个队列对交易图表,它被添加到一个字典中:
private Dictionary<string, BlockingCollection<tick>> tickQueues = new Dictionary<string, BlockingCollection<tick>>();
我在一小时后检查内存转储,我可以看到以下项目堆积起来:
Count Size(bytes) Inclusive Size
ThreadPoolWorkQueue+QueueSegment 22,951 24,236,256 40,316,868
QueueUserWorkItemCallback 689,838 13,796,760 16,081,272
TimerQueueTimer 11,160 713,772 2,355,736
我有一个负责将数据添加到队列的计时器:
private void TickTimer_tick(object source, ElapsedEventArgs e) {
if (Monitor.TryEnter(LockTimerTick, GlobalSettings.APISleepDelayMSTick)) {
updateLockFailCount = 0;
try {
tick t = new tick(DateTime.Now, d.bid, d.ask);
lastBid = d.bid;
lastAsk = d.ask;
t.pair = Inst.pair;
//myTickQueue.TryAdd(t);
if (!myTickQueue.TryAdd(t)) {
functions.Logger.log("Error when adding Tick on Queue for " + Inst.pair+ " Maybe Queue is full", "SHMAPI", LOGLEVEL.WARN);
}
} catch (Exception E) {
functions.Logger.log("Error happened when refreshing tick data: " + E.Message, "SHMAPI", LOGLEVEL.ERROR);
} finally {
Monitor.Exit(LockTimerTick);
}
} else {
updateLockFailCount++;
int sev = LOGLEVEL.TRACE;
if (updateLockFailCount == 10) { sev = LOGLEVEL.DEBUG; }
if (updateLockFailCount==50) { sev = LOGLEVEL.WARN; }
if (updateLockFailCount % 100 == 0 && updateLockFailCount>=100) { sev = LOGLEVEL.ERROR; }
functions.Logger.log("Could not get lock to refresh tick data for symbol "+Symbol, "SHMAPI", sev);
}
}
最后,我的任务是检查Q:
public void startQueueTask(string Pair) {
if (!tickQueues.ContainsKey(Pair.ToUpper())) {
tickQueues.Add(Pair.ToUpper(), new BlockingCollection<tick>(GlobalSettings.tickQueueSize));
if (!MTAPIs.ContainsKey(Pair.ToUpper())) {
throw new Exception("API for pair " + Pair + " Should be initialized !!");
}
MTAPIs[Pair.ToUpper()].setTickQueue(tickQueues[Pair.ToUpper()]);
functions.Logger.log("Starting " + Pair + " Queue Task", "TICKPROCESSING", LOGLEVEL.DEBUG);
Task.Run(() => {
foreach (tick tick in tickQueues[Pair.ToUpper()].GetConsumingEnumerable()) {
try {
onTick(tick);
} catch (Exception E) {
functions.Logger.log("Error processing tick for symbol " + tick.pair + " " + E.Message, "TICKPROCESSING", LOGLEVEL.ERROR);
functions.printException(E);
}
}
functions.Logger.log("Exiting Queue Task", "TICKPROCESSING", LOGLEVEL.ERROR);
});
} else {
functions.Logger.log("Skipping " + Pair + " Queue Task because already exists", "TICKPROCESSING", LOGLEVEL.DEBUG);
}
}
我不确定为什么我会收到OOM,但它看起来类似于: http://blogs.microsoft.co.il/bnaya/2012/02/26/real-life-story-blocking-collection/ 但我不是在这里使用并行...虽然周末市场已关闭,但我的队列是空的。 使用TryDequeue的另一个计时器会更好吗? 欢迎任何建议!
答案 0 :(得分:0)
我将计时器切换为手动,如下所示:
private void TickTimer_tick(object source, ElapsedEventArgs e) {
try {
//...
} finally {
TickTimer.Start();
}
}
它似乎解决了我的问题。 我也确保在Q中发送tick,并且它们由Receiver重复过滤,因此Queing线程永远不会等待太长时间。 谢谢你的指针!