Прежде всего, вы распараллеливаете повторные прогоны. Это улучшит ваше время тестирования, но может не сильно помочь вашему реальному рабочему времени. Чтобы точно измерить, сколько времени потребуется, чтобы на самом деле пройти через один список слов, вам нужно иметь ровно один список слов, идущий за раз. В противном случае отдельные потоки, обрабатывающие все списки, в некоторой степени конкурируют друг с другом за системные ресурсы, и время для каждого списка страдает, даже если время для выполнения всех списков в целом быстрее.
Чтобы ускорить обработку одного списка слов, вы хотите обрабатывать отдельные слова в списке параллельно, ровно по одному списку за раз. Чтобы получить достаточное определение / размер для хорошего измерения, либо сделайте список очень длинным, либо обработайте список много раз в последовательном порядке.
В вашем случае это становится немного сложнее, потому что построитель строк, необходимый для вашего конечного продукта, не описан как поточно-ориентированный. Это не так уж и плохо. Вот пример вызова параллельного foreach для списка из одного слова:
var locker = new Object(); //I'd actually make this static, but it should end up as a closure and so still work
var OutputBuffer = new StringBuilder(); // you can improve things futher if you can make a good estimate for the final size and force it allocate all the memory it will need up front
int score = 0;
Parallel.ForEach(words, w =>
{
// We want to push as much of the work to the individual threads as possible.
// If run in 1 thread, a stringbuilder per word would be bad.
// Run in parallel, it allows us to do a little more of the work outside of locked code.
var buf = new StringBuilder(w.Length + 5);
string word = buf.Append(w.Where(c=>c!='U').Concat(' ').ToArray()).Append(w.Length).ToString();
lock(locker)
{
OutputBuffer.Append(word);
score += w.Length;
}
});
OutputBuffer.Append("Total = ").Append(score);
Просто вызовите это 20 раз в обычном последовательно обработанном цикле for. Опять же, он может закончить тесты немного медленнее, но я думаю, что он будет работать в реальном мире немного быстрее из-за недостатка вашего теста. Также обратите внимание, что я набрал это прямо в окне ответа & mdash; Я никогда не пытался скомпилировать событие, и поэтому оно вряд ли будет идеальным прямо из ворот.
После исправления эталонного теста, чтобы более точно отразить, как параллельный код повлияет на ваше реальное время обработки, следующим шагом будет выполнить некоторое профилирование , чтобы увидеть, где на самом деле находится ваша программа. тратить время Вот как вы узнаете, на какие области нужно обратить внимание.
Из любопытства я также хотел бы знать, как работает эта версия:
var agg = new {score = 0, OutputBuffer = new StringBuilder()};
agg = words.Where(w => w.Length == 3)
.Select(w => new string(w.Where(c => c!='U').ToArray())
.Aggregate(agg, (a, w) => {a.OutputBuffer.AppendFormat("{0} {1}\n", w, w.Length); score += w.Length;});
agg.OutputBuffer.Append("Total = ").Append(score);