На C#: методами asparallel - ли того дело?
Я создаю простой запрос LinQ-to-object, который я хотел бы распараллелить, однако мне интересно, имеет ли значение порядок операторов ?
например
IList<RepeaterItem> items;
var result = items
.Select(item => item.FindControl("somecontrol"))
.Where(ctrl => SomeCheck(ctrl))
.AsParallel();
и
var result = items
.AsParallel()
.Select(item => item.FindControl("somecontrol"))
.Where(ctrl => SomeCheck(ctrl));
будет ли какая-то разница ?
2 ответов
абсолютно. В первом случае проекция и фильтрация будут выполняться последовательно, и только затем ничего быть распараллелен.
во втором случае и проекция, и фильтрация будут происходить параллельно.
Если у вас нет особой причины использовать первую версию (например, проекция имеет сродство с потоком или какую-то другую странность), вы должны использовать вторую.
EDIT: вот некоторый тестовый код. Недостатки, как многие ориентиры, но результаты достаточно убедительны:--5-->
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
class Test
{
static void Main()
{
var query = Enumerable.Range(0, 1000)
.Select(SlowProjection)
.Where(x => x > 10)
.AsParallel();
Stopwatch sw = Stopwatch.StartNew();
int count = query.Count();
sw.Stop();
Console.WriteLine("Count: {0} in {1}ms", count,
sw.ElapsedMilliseconds);
query = Enumerable.Range(0, 1000)
.AsParallel()
.Select(SlowProjection)
.Where(x => x > 10);
sw = Stopwatch.StartNew();
count = query.Count();
sw.Stop();
Console.WriteLine("Count: {0} in {1}ms", count,
sw.ElapsedMilliseconds);
}
static int SlowProjection(int input)
{
Thread.Sleep(100);
return input;
}
}
результаты:
Count: 989 in 100183ms
Count: 989 in 13626ms
теперь в PFX происходит много эвристических вещей, но довольно очевидно, что первый результат не был распараллелен вообще, в то время как второй.
это имеет значение, и не только в производительности.
Результаты первого и второго запросов не равны.
Существует решение для параллельной обработки и сохранения исходного порядка.
Использовать AsParallel().AsOrdered()
. Третий запрос показывает это.
var SlowProjection = new Func<int, int>((input) => { Thread.Sleep(100); return input; });
var Measure = new Action<string, Func<List<int>>>((title, measure) =>
{
Stopwatch sw = Stopwatch.StartNew();
var result = measure();
sw.Stop();
Console.Write("{0} Time: {1}, Result: ", title, sw.ElapsedMilliseconds);
foreach (var entry in result) Console.Write(entry + " ");
});
Measure("Sequential", () => Enumerable.Range(0, 30)
.Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Parallel", () => Enumerable.Range(0, 30).AsParallel()
.Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Ordered", () => Enumerable.Range(0, 30).AsParallel().AsOrdered()
.Select(SlowProjection).Where(x => x > 10).ToList());
результат:
Sequential Time: 6699, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Parallel Time: 1462, Result: 12 16 22 25 29 14 17 21 24 11 15 18 23 26 13 19 20 27 28
Ordered Time: 1357, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Я был удивлен этим, но результат был последовательным после 10+ тестового запуска. Я немного исследовал, и это оказалось "ошибкой" в .Net 4.0. В 4.5 AsParallel() не медленнее, чем Методами asparallel().AsOrdered ()
Ссылка здесь:
http://msdn.microsoft.com/en-us/library/dd460677 (v=против 110).aspx