【发布时间】:2022-01-26 12:17:19
【问题描述】:
我尝试多线程合并排序算法。该算法的简单形式是:(Merge() 是一种标准的合并算法)
static void MergeSort(this int[] array, int initial, int final) {
if (initial == final) return;
array.MergeSort(initial, (initial + final) / 2);
array.MergeSort((initial + final) / 2 + 1, final);
array.Merge(initial, final);
}
而多线程版本是:
static void MergeSortMT(this int[] array, int initial, int final, int mtCount) {
if (initial == final) return;
if (mtCount > 0) {
Task t = Task.Run(() =>
{
array.MergeSortMT(initial, (initial + final) / 2, mtCount - 1);
});
array.MergeSortMT((initial + final) / 2 + 1, final, mtCount - 1);
t.Wait();
}
else
{
array.MergeSort(initial, (initial + final) / 2);
array.MergeSort((initial + final) / 2 + 1, final);
}
array.Merge(initial, final);
}
这里的mtCount表示线程分离会发生多少次。通常整个排序由单个线程运行。如果 mtCount 为 1,总线程数变为 2,如果 mtCount 为 2,总线程数变为 4,以此类推。
以下是一些结果:
Method - Input Size - Times Run - Miliseconds
Merge 1000000 X 1000 606832
Merge 100000 X 1000 51061
Merge 10000 X 1000 4080
Merge 1000 X 1000 314
Merge 100 X 1000 22
Merge 10 X 1000 1
mtCount = 1
MergeMT 1000000 X 1000 258237
MergeMT 100000 X 1000 23498
MergeMT 10000 X 1000 2088
MergeMT 1000 X 1000 202
MergeMT 100 X 1000 57
MergeMT 10 X 1000 44
mtCount = 2
MergeMT 1000000 X 1000 188337
MergeMT 100000 X 1000 16836
MergeMT 10000 X 1000 1825
MergeMT 1000 X 1000 355
MergeMT 100 X 1000 162
MergeMT 10 X 1000 299
mtCount = 3
MergeMT 1000000 X 1000 175220
MergeMT 100000 X 1000 15276
MergeMT 10000 X 1000 1690
MergeMT 1000 X 1000 455
MergeMT 100 X 1000 296
MergeMT 10 X 1000 416
mtCount = 4
MergeMT 1000000 X 1000 197234
MergeMT 100000 X 1000 17046
MergeMT 10000 X 1000 2087
MergeMT 1000 X 1000 684
MergeMT 100 X 1000 657
MergeMT 10 X 1000 596
因此,使用 2 个线程可以将代码优化 2 倍以上。使用 4 个线程影响较小,8 个线程几乎没有任何好处。使用 16 个线程甚至会降低性能,这是可以理解的。 (小的输入大小并不重要。我知道启动一个新线程需要一些时间。)
知道我的计算机有 4 个物理内核和 8 个线程,我的问题是为什么使用 4 或 8 个线程对性能的提升要少得多?
【问题讨论】:
-
我使用 System.Diagnostics 中的 Stopwatch 类来计算时间。如果我运行 ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads); workerThreads 设置为 8。
-
“我知道创建一个新线程需要一些时间”,您没有回答自己的问题吗?
-
您是否尝试过使用任务并行库 (TPL) 进行并行化?
-
“我的电脑有 4 个物理核心”作为@Sefe 提示,如果你想在核心之间分配工作,你应该使用 TPL
-
您可以尝试流式传输最后的合并步骤,以便它们可以在前一个排序完成之前开始。
标签: c# multithreading