首次创建使用并行 linq 的方法并出现内存不足异常

本文关键字:方法 异常 内存不足 linq 创建 并行 | 更新日期: 2023-09-27 18:32:51

我写了一个从互联网下载数据并将其保存到我的数据库的方法。我使用 PLINQ 编写了这篇文章,以利用我的多核处理器,因为它在很短的时间内下载了数千个不同的文件。我在代码中添加了下面的注释以显示它停止的位置,但程序只是坐在那里,过了一会儿,我得到一个内存不足异常。这是我第一次使用 TPL 和 PLINQ,我非常困惑,所以我真的可以使用一些关于如何解决这个问题的建议。

更新:我发现我不断收到网络异常,因为网络客户端超时。我根据这里的答案通过增加最大连接量来解决此问题。然后我收到了连接未打开的异常,我在这里使用此答案修复了它。我现在收到数据库的连接超时错误,即使它是本地 sql 服务器。我仍然无法运行我的任何代码,所以我完全可以使用一些建议

static void Main(string[] args)
    {
        try
        {
            while (true)
            {
                // start the download process for market info
                startDownload();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }
    }
    public static void startDownload()
    {
        DateTime currentDay = DateTime.Now;
        List<Task> taskList = new List<Task>();
        if (Helper.holidays.Contains(currentDay) == false)
        {
            List<string> markets = new List<string>() { "amex", "nasdaq", "nyse", "global" };
            Parallel.ForEach(markets, market =>
            {
                Downloads.startInitialMarketSymbolsDownload(market);
            }
            );
            Console.WriteLine("All downloads finished!");
        }
        // wait 24 hours before you do this again
        Task.Delay(TimeSpan.FromHours(24)).Wait();
    }
public static void startInitialMarketSymbolsDownload(string market)
    {
        try
        {
            List<string> symbolList = new List<string>();
            symbolList = Helper.getStockSymbols(market);
            var historicalGroups = symbolList.AsParallel().Select((x, i) => new { x, i })
                      .GroupBy(x => x.i / 100)
                      .Select(g => g.Select(x => x.x).ToArray());
            historicalGroups.AsParallel().ForAll(g => getHistoricalStockData(g, market));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }
    }
public static void getHistoricalStockData(string[] symbols, string market)
    {
        // download data for list of symbols and then upload to db tables
        Uri uri;
        string url, line;
        decimal open = 0, high = 0, low = 0, close = 0, adjClose = 0;
        DateTime date;
        Int64 volume = 0;
        string[] lineArray;
        List<string> symbolError = new List<string>();
        Dictionary<string, string> badNameError = new Dictionary<string, string>();
        Parallel.ForEach(symbols, symbol =>
                {
                        url = "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&a=00&b=1&c=1900&d=" + (DateTime.Now.Month - 1) + "&e=" + DateTime.Now.Day + "&f=" + DateTime.Now.Year + "&g=d&ignore=.csv";
                        uri = new Uri(url);
                        using (dbEntities entity = new dbEntities())
                        using (WebClient client = new WebClient())
                        using (Stream stream = client.OpenRead(uri))
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            while (reader.EndOfStream == false)
                            {
                                line = reader.ReadLine();
                                lineArray = line.Split(',');
                                // if it isn't the very first line
                                if (lineArray[0] != "Date")
                                {
                                    // set the data for each array here
                                    date = Helper.parseDateTime(lineArray[0]);
                                    open = Helper.parseDecimal(lineArray[1]);
                                    high = Helper.parseDecimal(lineArray[2]);
                                    low = Helper.parseDecimal(lineArray[3]);
                                    close = Helper.parseDecimal(lineArray[4]);
                                    volume = Helper.parseInt(lineArray[5]);
                                    adjClose = Helper.parseDecimal(lineArray[6]);
                                    switch (market)
                                    {
                                        case "nasdaq":
                                            DailyNasdaqData nasdaqData = new DailyNasdaqData();
                                            var nasdaqQuery = from r in entity.DailyNasdaqDatas.AsParallel().AsEnumerable()
                                                              where r.Date == date
                                                              select new StockData { Close = r.AdjustedClose };
                                            List<StockData> nasdaqResult = nasdaqQuery.AsParallel().ToList(); // hits this line
                                            break;
                                        default:
                                            break;
                                    }
                                }
                            }
                            // now save everything
                            entity.SaveChanges();
                        }
                }
        );
    }

首次创建使用并行 linq 的方法并出现内存不足异常

异步 lambda 在一个方面的工作方式类似于异步方法:它们不同步完成,但它们返回一个 Task。在并行循环中,您只需尽可能快地生成任务。这些任务保留内存和其他资源,例如数据库连接。

最简单的解决方法可能是只使用同步数据库提交。这不会导致吞吐量损失,因为数据库无论如何都无法处理大量并发 DML。