c# - 如何将列表的子集添加到另一个列表中对象的属性 - 最佳/最快实践
问题描述
我试图找到最快和最高效的方法来根据关键属性从列表中选择项目的子集,并将这个子集(列表)分配给另一个列表中项目的属性。性能方面很重要,因为这部分代码将在每个工作日被非常频繁地调用。我以刻度测量了性能,以清楚地看到相对差异。
我有两个列表(示例设置);
List<CategorySetting> catList;
List<Customer> custList;
该CategorySetting
实体有一个名为 的属性SettingsId
。该Customer
实体也有一个SettingsId
属性,它实际上是一个来自Customers
to的外键CategorySetting
。
我写的第一段代码是最直接的;
// normal for each: 13275 ticks
foreach (var catItem in catList)
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
}
这将需要大约 13275 个滴答声。
然后我想也许使用并行性这可能会快很多?所以我写了这段代码;
// parallel for each: 82541 ticks
Parallel.ForEach(catList, catItem =>
{
catItem.Customers = custList.Where(c => c.SettingsId == catItem.SettingsId).ToList();
});
这需要更长的时间。82541 滴答声。由于这种方法的并行性,这对我来说毫无意义。它应该使用多个线程来执行此操作,因此理论上应该更快。然后我开始想知道如果多个线程同时尝试访问客户列表会发生什么。这可能会导致锁和队列,因此由于开销而需要更多时间?与写入主列表相同。
我尝试了另一种方法。我ConcurrentBag
为 catList(主列表)做了一个。
ConcurrentBag<CategorySettings> csBag = new ConcurrentBag<CategorySettings>(catList);
我加入的 custListConcurrentDictionary
已经按SettingsId
.
var dict = custList.GroupBy(c => c.SettingsId).ToDictionary(x => x.Key, y => y.ToList());
ConcurrentDictionary<int?, List<Customer>> concDict = new ConcurrentDictionary<int?, List<Customer>>(dict);
最后的尝试是这样的:
// paralell, bag, concurrent dictionary: 40255
Parallel.ForEach(caBag, ca =>
{
concDict.TryGetValue(ca.SettingsId, out var selCust);
ca.Customers = selCust;
});
这需要 40255 个滴答声。谁能解释为什么这仍然需要更长的时间?更重要的是,除了“只是”一个 foreach 循环之外,没有其他方法了吗?感觉就像我在这里错过了一些东西。
任何想法都非常感谢!
解决方案
您可以尝试使用ToLookup
LINQ 方法:
var customersLookup = custList.ToLookup(item => item.SettingsId);
foreach (var catItem in catList)
{
catItem.Customers = customersLookup[catItem.SettingsId].ToList();
}
我假设CategorySetting
该类具有Customers
type的可写属性IList<Customer>
。如果属性是 type IEnumerable<Customer>
,您可以省略ToList
调用。
推荐阅读
- callback - 在Julia中DifferentialEquations.jl的ODE求解器中的每个常规时间间隔回调
- python - 如何有效地将一个DF的多列附加到另一个DF的一列中
- ruby-on-rails - 无需重新渲染整个页面即可访问更新的数据
- python - 如何在 python 中接受第三方 cookie 到 selenium chromedriver?
- javascript - 按下按钮时创建警报
- angular - 嵌套路由器:父路由有效,子路由无
- python - 在包中使用 -m 开关和 __main__.py 文件有什么区别 - 因为两者都允许运行文件而不需要指定 .py?
- javascript - 获取参数拉取相同的id
- javascript - 如何在javascript中导入张量流?导入文件,由本地 http-server 提供服务
- linux - Linux如何查找命令删除多个文件?