列表上的C#Foreach非常慢



我有一个经过responseforeachresponse是一个最多可以占用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亿个元素,但一旦超过几千个元素,你就会开始遇到麻烦。它们并不是真正用于您尝试的那种繁重的数据处理这正是数据库引擎的作用所在。

最新更新