我有一个 IEnumerable<IEnumerable<T>>
方法称为 Batch
就像
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));
-->
1,2
4,8
10,-4
3
我遇到的问题是我要优化类似
的东西foreach(var batch in batches)
ExecuteBatch(batch);
通过
Task[] tasks = batches.Select(batch => Task.Factory.StartNew(() => ExecuteBatch(batch))).ToArray();
Task.WaitAll(tasks);
或
Action[] executions = batches.Select(batch => new Action(() => ExecuteBatch(batch))).ToArray();
var options = new ParallelOptions { MaxDegreeOfParallelism = 4 };
Parallel.Invoke(options, executions);
(因为 ExecuteBatch
是涉及 IO 的长时间运行的操作)
然后我注意到每个 batch
搞砸了,只有 1 个元素,即 default(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());
}
最佳答案
如评论中所述,您的实际问题是您对 Batch
的实现。
这段代码:
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)
结束了)。
这是 Batch
的一个实现,它在具体化时(因此在并行时)会起作用。
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;
}
关于c# - 并行调用 IEnumerable 的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45179750/