gpt4 book ai didi

c# - 带有延迟加载列表的并行 Foreach

转载 作者:太空宇宙 更新时间:2023-11-03 15:09:30 25 4
gpt4 key购买 nike

我正在使用 Entity Framework,并且我有一个列表,我需要遍历它来处理它。我无法直接通过数据库查询来完成这项工作,而且列表可能会很大,所以我希望我可以使用 Parallel Foreach 或 AsParallel。

问题是,即使我使用 ToList() 将我的列表加载到内存中,然后在并行函数中运行它,它也会破坏我的延迟加载导航属性。

我正在运行这样简单的东西(为了这个问题的目的,这已经被简化了很多):

var quoteList = DbContext.Quotes.ToList();

List<QuotesItem> quoteViewItemList = new List<QuotesItem>();

quoteList.ForAll(quote => {
var quoteViewItem = new QuotesItem();
quoteViewItem.YearEnding = quote.QuoteService.FirstOrDefault().Yearending; //is SOMETIMES null when it shouldn't be.
quoteViewItem.Manager quote.Client.Manager.Name; //IS sometimes null
quoteViewItem.... = ..... // More processing here
quoteViewItemList.Add(quoteViewItem);
});

问题是 QuoteService 有时似乎为空,即使它在列表中不为空。

最佳答案

首先让我们谈谈这个问题。我可以想象的唯一原因是在 .ForAll 完成其工作之前处理 DbContext,可能来自不同的线程?但我目前只是猜测。

我可以给你一些关于可能的代码优化的建议。如果数据库中有很多记录,首先使用 .ToList() 评估所有报价可能会对性能产生一些影响,所以我在这里的建议是用 SQL 游标交换急切评估。这可以通过使用内部使用 IEnumerable<> 和更具体的 .GetEnumerator() 的任何构造/代码来实现。

EF 中 IQueriable<> 的内部实现创建了一个 SQL 游标,速度非常快。最好的部分是您可以将它与 .AsParallel() 或 Parallel.ForEach 一起使用,两者都在内部使用枚举器。

这不是一个非常有记录的功能,但是如果启动 SQL Server Profile 并执行下面的代码,您会看到只有一个请求被执行到服务器,而且您会注意到执行代码的机器的 RAM 没有峰值,这意味着它不会一次获取所有内容。

如果您有兴趣,我已经找到了一些关于它的随机信息:https://sqljudo.wordpress.com/2015/02/24/entity-framework-hidden-cursors/

虽然我在操作数据库记录的代码非常繁重的情况下使用了这种方法,但对于从一种类型到另一种类型的简单投影,使用 .AsParallel( .. ) 运行游标或简单的 foreach 构造可能执行类似。

所以使用

DbContext.Quotes
.AsParallel()
.WithDegreeOfParallelism(...)
.ForAll(...)

应该以良好的性能运行。

我的第二个建议是关于使用延迟加载访问 EF 中的导航属性。如您所知,这会导致 N+1 选择问题。因此,在这种情况下,与其依赖 EF 惰性评估,不如急切获取导航属性会更好,因此我们可以将代码重写为这样

 DbContext.Quotes
.Include(x => x.QuoteService)
.AsParallel()
.WithDegreeOfParallelism(...)
.ForAll(...)

这种方式在访问 QuoteService 导航属性时 EF 不会对服务器执行任何额外的请求,因此这应该会显着提高您的性能并且它可能可以神奇地修复 Null 引用问题(我希望)

我正在使用 System.Data.Entity 命名空间的一部分的 .Include(..) 方法的通用版本。

此外,如果您的方案可以接受,您可以禁用更改跟踪,这将使您获得更多性能。所以我的最终代码将如下所示

  var queryViewItems = DbContext.Quotes
.AsNoTracking()
.Include(x => x.QuoteService)
.AsParallel()
.WithDegreeOfParallelism(...)
.Select(x => { ... })
.ToList();

关于c# - 带有延迟加载列表的并行 Foreach,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41842467/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com