首页 > 解决方案 > 处理来自套接字流的数据时,集合被修改错误

问题描述

我正在尝试从 Binance 聚合数据流中捕获刻度级别数据。一旦日期更改,函数就会处理前一天的数据。我正在使用 Task.Run 创建另一个线程,因为当天的新数据仍在流入并需要捕获。但是,我收到“集合已修改,枚举操作可能无法执行”。在处理数据的函数的 foreach 循环中。我不确定为什么 tradeData 在传递给处理函数后会被修改?不确定这是否重要,但我在不同的线程上捕获了大约 40 个不同的符号。

private static void Start()
{
    foreach (SymbolData symbol in symbolData)
    {
         Task.Run(() => SubscribeToSymbol(symbol.symbol));
    }
}

private static void SubscribeToSymbol(string symbol)
{
    Dictionary<decimal, decimal> tradeData = new Dictionary<decimal, decimal>();
    DateTime lastTrade = DateTime.UtcNow;
    try
    {
         var socketClient = new BinanceSocketClient();
         socketClient.FuturesUsdt.SubscribeToAggregatedTradeUpdates(symbol, data =>
         {
              if (data.TradeTime.Date > lastTrade.Date)
              {
                   Task.Run(() => ProcessData(symbol, lastTrade.Date, tradeData));
                   tradeData.Clear();
              }
              lastTrade = data.TradeTime;

              if (tradeData.ContainsKey(data.Price))
              {
                   tradeData[data.Price] = tradeData[data.Price] + data.Quantity;
              }
              else
              {
                   tradeData[data.Price] = data.Quantity;
              }
         });
     }
     catch { }
}


private static void ProcessData(string symbol, DateTime date, Dictionary<decimal, decimal> tradeData)
{
     foreach (var price in tradeData)
     {
     //Error: Collection was modified enumeration operation may not execute.
     }
}

标签: c#financealgorithmic-tradingbinance

解决方案


您重复调用 Task.Run ,结果有多个线程在处理您的 tradeData 对象,这就是您看到集合修改异常的原因。

我建议您重新考虑代码设计,以免多个线程处理相同的对象。如果您绝对必须让线程处理相同的对象,那么应该使用 lock:

private static object _objlock = new object();

private static void ProcessData(string symbol, DateTime date, Dictionary<decimal, decimal> tradeData)
{
    lock (_objlock)
    {
        foreach (var price in tradeData)
        {
     
        }
     }
}

使用锁时要小心死锁。我建议阅读 C# 中的锁和多线程。


推荐阅读