为什么在使用线程时,以下代码的性能会降低?
** 1.没有线程
int[] arr = new int[100000000]; //Array elements - [0][1][2][3]---[100000000-1]
addWithOutThreading(arr); // Time required for this operation - 1.16 sec
addWithOutThreading的定义
public void addWithOutThreading(int[] arr)
{
UInt64 result = 0;
for (int i = 0; i < 100000000; i++)
{
result = result + Convert.ToUInt64(arr[i]);
}
Console.WriteLine("Addition = " + result.ToString());
}
** 2.带线程
int[] arr = new int[100000000];
int part = (100000000 / 4);
UInt64 res1 = 0, res2 = 0, res3 = 0, res4 = 0;
ThreadStart starter1 = delegate
{ addWithThreading(arr, 0, part, ref res1); };
ThreadStart starter2 = delegate
{ addWithThreading(arr, part, part * 2, ref res2); };
ThreadStart starter3 = delegate
{ addWithThreading(arr, part * 2, part * 3, ref res3); };
ThreadStart starter4 = delegate
{ addWithThreading(arr, part * 3, part * 4, ref res4); };
Thread t1 = new Thread(starter1);
Thread t2 = new Thread(starter2);
Thread t3 = new Thread(starter3);
Thread t4 = new Thread(starter4);
t1.Start();
t2.Start();
t3.Start();
t4.Start();
t1.Join();
t2.Join();
t3.Join();
t4.Join();
Console.WriteLine("Addition = "+(res1+res2+res3+res4).ToString());
// Time required for this operation - 1.30 sec
addWithThreading的定义
public void addWithThreading(int[] arr,int startIndex, int endIndex,ref UInt64 result)
{
for (int i = startIndex; i < endIndex; i++)
{
result = result + Convert.ToUInt64(arr[i]);
}
}
答案 0 :(得分:8)
您所说的操作已经相当快,在创建线程和使所有内容正常运行时会产生性能开销。很可能你的线程创建,数组的拆分和所需的额外计算都构成了额外的时间。
答案 1 :(得分:3)
最可能的原因是您的问题不足以克服启动线程的固有开销。并且,正如您指示您只有2个内核,如果您没有I / O,则使用4个线程是过度的。在任何给定时间最多可以运行2个线程,因此只有4个线程才能确保您有一些不必要的上下文切换。
对于大问题,也可能是你可能遇到内存抖动问题。在这种情况下,这不太可能,但是你已经分解了你的工作,以便每个线程处理不同的内存块。这些可以位于不同的页面上,如果内存是瓶颈,它可能会换出一个线程使用的页面来引入另一个页面所需的页面。每次切换上下文时,都可能需要执行此页面交换。构造问题的更好方法是让每个线程i
在i
行开始,然后按线程数来逐行。这样,假设线程以大致相同的速率运行,线程的引用位置是相同的,它们都在相同的页面上工作 - 没有颠簸。
答案 2 :(得分:0)
或许线程的开销大于任何性能节省。尝试对其进行扩展(IE,使100000000
更大)以查看性能是否仍有相同类型的差距。
答案 3 :(得分:0)
如果你正在做一些CPU密集型的事情,那么拥有多个线程的用途有限,如果你超过了硬件线程的数量(因此Ivan关于超线程的问题)。
如果您有线程写入文件或从文件中读取,那么您将看到差异。
如果你有一个cpu / core,那么一切都以单线程的形式运行,因为一次只有一个线程可以做某事。
为什么不尝试每次都有一个短暂睡眠的测试,模拟等待一些较慢的资源,然后你就可以看到多个线程的好处。