GetPartitions получил перекос разделов?
Выполнение следующего кода в интерактивном окне C#
using System.Collections.Concurrent;
var l = Enumerable.Range(0, 20);
Partitioner.Create(l).GetPartitions(4)
.Select(x => {
var s = "";
while (x.MoveNext()) { s += x.Current.ToString() + ","; };
return s;
})
возвращается
Enumerable.WhereSelectArrayIterator<IEnumerator<int>, string>
{ "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,", "", "", "" }
Кажется, один раздел получил все значения? Я попробовал это с большим размером Enumerable.Range(0, 12000)
и все элементы все еще идут в первом разделе.
Я хочу убедиться, что следующий метод расширения может равномерно разделить список.
public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(dop)
select Task.Run(async delegate {
using (partition)
while (partition.MoveNext())
await body(partition.Current);
}));
}
1 ответ
Решение
Я скажу, что это ваш код, который вызывает его: вы перечисляете только один раздел, но разделы "заполняются" по запросу.
Вы хотите простой тест?
Partitioner.Create(l).GetPartitions(4)
.Skip(1)
.Select(x => {
var s = "";
while (x.MoveNext()) { s += x.Current.ToString() + ","; };
return s;
})
Теперь это еще один раздел, который получает все значения:-) Но не был ли первый раздел, который получил все значения? Теперь это второй:-)
Более правильным тестом будет:
var l = Enumerable.Range(0, 20);
var parts = Partitioner.Create(l).GetPartitions(4);
string[] bufs = new string[parts.Count];
while (true)
{
int countFinished = 0;
for (int i = 0; i < parts.Count; i++)
{
if (parts[i].MoveNext())
{
bufs[i] += parts[i].Current + ",";
}
else
{
countFinished++;
}
}
if (countFinished == parts.Count)
{
break;
}
}
for (int i = 0; i < parts.Count; i++)
{
Console.WriteLine(bufs[i]);
}
Я перечисляю четыре раздела одновременно. Это распределит все числа поровну между разделами.