我有一个经过response
的foreach
,response
是一个最多可以占用230000条记录的列表,foreach response
它将过滤并求和第二个名为_MaterialIssued
的列表,该列表最多包含30000条记录,在下面的if
中,只有当Issued
大于0时才会输入,这只会发生大约15%的时间,接下来,它将尝试从包含最多17000条记录的_Onhand
列表中获取itemOnhand
,在接下来的if
中,它将在大约85%的时间内进行,当我在这个块中编写代码时,性能急剧下降,在这个if
中,我将返回并筛选所有子项的response
,并在它们之间循环,更改_onhand
列表和response
列表!
完成这个foreach
取决于我使用的机器,但需要45到75分钟,我找不到哪一行是我的瓶颈,也找不到如何提高这个代码块的性能。
foreach (var b in response)
{
var Issued = _MaterialIssued.Where(x => x.ItemId == b.ItemId && x.Job == b.Job).Sum(c => c.Qty);
if (Issued > 0)
{
var prctIssued = Issued / b.QtyDemand;
var childItems = response.Where(x => x.Job == b.Job && x.BomPath.StartsWith(b.BomPath));
foreach (var child in childItems)
{
child.QtyIssued = child.QtyDemand * prctIssued;
}
}
var itemOnhand = _OnHand.Where(x => x.ItemId == b.ItemId).FirstOrDefault();
if (itemOnhand.Onhand > 0)
{
decimal prctOnhand = 1;
var childItems = response.Where(x => x.Job == b.Job && x.BomPath.StartsWith(b.BomPath) && x.ItemId != b.ItemId && x.SiteRef == b.SiteRef && x.QtyIssued < x.QtyDemand);
var DemandWithIssued = b.QtyDemand - b.QtyIssued;
if (itemOnhand.Onhand < DemandWithIssued)
{
prctOnhand = itemOnhand.Onhand / DemandWithIssued;
}
itemOnhand.Onhand -= DemandWithIssued * prctOnhand;
foreach (var child in childItems)
{
child.QtyParentAvailable = (child.QtyDemand - child.QtyIssued) * prctOnhand;
}
}
}
_OnHand
的型号为
private class ItemOnhand
{
public string ItemId { get; set; }
public string SiteRef { get; set; }
public decimal Onhand { get; set; }
}
_MaterialIssued
的型号为
public class FiniteDemandBase
{
public string ItemId { get; set; }
public string Item { get; set; }
public string JobId { get; set; }
public string Job { get; set; }
public DateTime StartDate { get; set; }
public string SiteRef { get; set; }
public decimal Qty { get; set; }
}
response
的型号为
public class FiniteDemand
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public string BomPath { get; set; }
public string SiteRef { get; set; }
public string Job { get; set; }
public string ItemId { get; set; }
public string JobId { get; set; }
public string ParentItemId { get; set; }
public decimal QtyPerUnit { get; set; }
public decimal QtyDemand { get; set; }
public decimal QtyOnhand { get; set; }
public decimal QtyWip { get; set; }
public decimal QtyOnhandRunning { get; set; }
public decimal QtyInSchedule { get; set; }
public decimal QtyIssued { get; set; }
public decimal QtyParentAvailable { get; set; }
public decimal QtyDemandNeeded { get; set; }
public decimal QtyDemandNeededRunning { get; set; }
}
我尝试将_OnHand
列表更改为HashSet
,但性能相同。
让我们将代码分解为包含显式或隐式迭代的部分:
response
-n
-次的迭代:
foreach (var b in response)
{
_MaterialIssued
-m
-次的嵌套迭代:
var Issued = _MaterialIssued.Where(x => x.ItemId == b.ItemId && x.Job == b.Job).Sum(c => c.Qty);
response
上的嵌套迭代(再次)--n
-次:
var childItems = response.Where(x => x.Job == b.Job && x.BomPath.StartsWith(b.BomPath));
_OnHand
上的嵌套迭代——最多h
次:
var itemOnhand = _OnHand.Where(x => x.ItemId == b.ItemId).FirstOrDefault();
response
上的嵌套迭代(再次)--n
-次:
var childItems = response.Where(x => x.Job == b.Job && x.BomPath.StartsWith(b.BomPath) && x.ItemId != b.ItemId && x.SiteRef == b.SiteRef && x.QtyIssued < x.QtyDemand);
因此,您的算法的复杂度为:O(n * (m + n + h + n)) = O(2*n^2 + n*(m+h))
!
如果响应的数量是230000,我们说的是52.9亿次迭代!难怪它会运行很长时间:)
这听起来很像是在管理数据库。我建议你一直这样做,并考虑使用类似MySQL
的东西。
例如:
在Visual Studio 中创建数据库并添加表
使用ADO.NET和Visual C#.NET 以编程方式创建SQL Server数据库
虽然从技术上讲,List
可以包含多达20亿个元素,但一旦超过几千个元素,你就会开始遇到麻烦。它们并不是真正用于您尝试的那种繁重的数据处理这正是数据库引擎的作用所在。