C# IEnumerable元素的并行调用
我有一个名为C# IEnumerable元素的并行调用,c#,.net,linq,asynchronous,parallel-processing,C#,.net,Linq,Asynchronous,Parallel Processing,我有一个名为Batch的IEnumerable方法,其工作原理如下 var list = new List<int>() { 1, 2, 4, 8, 10, -4, 3 }; var batches = list.Batch(2); foreach(var batch in batches) Console.WriteLine(string.Join(",", batch)); 我遇到的问题是,我要优化如下内容 foreach(var batch in batches)
Batch
的IEnumerable
方法,其工作原理如下
var list = new List<int>() { 1, 2, 4, 8, 10, -4, 3 };
var batches = list.Batch(2);
foreach(var batch in batches)
Console.WriteLine(string.Join(",", batch));
我遇到的问题是,我要优化如下内容
foreach(var batch in batches)
ExecuteBatch(batch);
借
或
(因为执行包是一个涉及IO的长时间运行的操作)
然后我注意到每个批处理都会出错,只有一个元素是默认值(int)
。知道发生了什么事或者怎么解决吗
批次:
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
for(var mover = source.GetEnumerator(); ;)
{
if(!mover.MoveNext())
yield break;
yield return LimitMoves(mover, size);
}
}
private static IEnumerable<T> LimitMoves<T>(IEnumerator<T> mover, int limit)
{
do yield return mover.Current;
while(--limit > 0 && mover.MoveNext());
}
公共静态IEnumerable批处理(此IEnumerable源,int-size)
{
对于(var mover=source.GetEnumerator();;)
{
如果(!mover.MoveNext())
屈服断裂;
收益率限制移动(移动器、大小);
}
}
私有静态IEnumerable LimitMoves(IEnumerator mover,int limit)
{
不产生回流。电流;
而(--limit>0&&mover.MoveNext());
}
如评论中所述,您的实际问题是批处理的实现
此代码:
for(var mover = source.GetEnumerator(); ;)
{
if(!mover.MoveNext())
yield break;
yield return LimitMoves(mover, size);
}
当Batch
具体化时,此代码将持续调用MoveNext()
,直到可枚举项用尽为止LimitMoves()
使用相同的迭代器,并被延迟调用。由于Batch
会耗尽可枚举项,LimitMoves()
将永远不会发出项。(实际上,它只会发出default(T)
,因为它总是返回mover.Current
,一旦枚举完成,它将成为default(T)
)
这里是批处理的一个实现,它在具体化时(因此在并行时)可以工作
公共静态IEnumerable批处理(此IEnumerable源,int-size)
{
var mover=source.GetEnumerator();
var currentSet=新列表();
while(mover.MoveNext())
{
currentSet.Add(mover.Current);
如果(currentSet.Count>=大小)
{
产生返回电流集;
currentSet=新列表();
}
}
如果(currentSet.Count>0)
产生返回电流集;
}
或者,您可以使用批处理实现中附带的-。你可以看到他们的实施你能详细说明一下这个问题吗?你是说批处理方法不起作用吗?在这种情况下,向我们展示it@Rob添加了实现您的问题是Batch
正在耗尽枚举器(它处于for循环中,并不断调用MoveNext()
在LimitMoves
有机会之前。实际的错误是由于使用ToArray()
实现集合而引起的,与并行性无关。如果将原始代码更改为var batches=list.Batch(2).ToList();
,您将看到相同的问题。
Action[] executions = batches.Select(batch => new Action(() => ExecuteBatch(batch))).ToArray();
var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };
Parallel.Invoke(options, executions);
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
for(var mover = source.GetEnumerator(); ;)
{
if(!mover.MoveNext())
yield break;
yield return LimitMoves(mover, size);
}
}
private static IEnumerable<T> LimitMoves<T>(IEnumerator<T> mover, int limit)
{
do yield return mover.Current;
while(--limit > 0 && mover.MoveNext());
}
for(var mover = source.GetEnumerator(); ;)
{
if(!mover.MoveNext())
yield break;
yield return LimitMoves(mover, size);
}
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
var mover = source.GetEnumerator();
var currentSet = new List<T>();
while (mover.MoveNext())
{
currentSet.Add(mover.Current);
if (currentSet.Count >= size)
{
yield return currentSet;
currentSet = new List<T>();
}
}
if (currentSet.Count > 0)
yield return currentSet;
}