multithreading比单线程慢

我有以下代码(控制台应用程序的’Program.cs’的完整内容)。 ‘countUp’直到’countUp4’的单线程执行需要13秒,multithreading执行21秒。

我有一个Intel Core i5-2400 @ 3.10 GHz,8 GB Ram,Windows 7 64 Bit。 那么为什么mutli线程执行比单线程执行慢?

multithreading对于不阻塞简单c#应用程序的主程序有用吗? multithreading什么时候给我一个执行速度的优势?

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ConsoleApplication1 { class Program { static int counter = 0; static int counter2 = 0; static int counter3 = 0; static int counter4 = 0; static void Main(string[] args) { Console.WriteLine("Without multithreading:"); Console.WriteLine("Start:" + DateTime.Now.ToString()); countUp(); countUp2(); countUp3(); countUp4(); Console.WriteLine(""); Console.WriteLine("With multithreading:"); Console.WriteLine("Start:" + DateTime.Now.ToString()); Thread thread1 = new Thread(new ThreadStart(countUp)); thread1.Start(); Thread thread2 = new Thread(new ThreadStart(countUp2)); thread2.Start(); Thread thread3 = new Thread(new ThreadStart(countUp3)); thread3.Start(); Thread thread4 = new Thread(new ThreadStart(countUp4)); thread4.Start(); Console.Read(); } static void countUp() { for (double i = 0; i < 1000000000; i++) { counter++; } Console.WriteLine(counter.ToString()); Console.WriteLine(DateTime.Now.ToString()); } static void countUp2() { for (double i = 0; i < 1000000000; i++) { counter2++; } Console.WriteLine(counter2.ToString()); Console.WriteLine(DateTime.Now.ToString()); } static void countUp3() { for (double i = 0; i < 1000000000; i++) { counter3++; } Console.WriteLine(counter3.ToString()); Console.WriteLine(DateTime.Now.ToString()); } static void countUp4() { for (double i = 0; i < 1000000000; i++) { counter4++; } Console.WriteLine(counter4.ToString()); Console.WriteLine(DateTime.Now.ToString()); } } } 

这是你可能看不到的原因: 错误分享,因为这4个整数都在内存中并排存在。

更新 – 前几年的MSDN mags现在仅作为.chm文件提供 – 所以你必须从这里获取MSDN Mag的’2008年10月版,并且在下载之后,你必须记住右键单击并“解锁”在打开它之前,从Windows资源管理器中的文件属性对话框中获取文件(其他操作系统可用!)。 您正在寻找由Stephen Toub,Igor Ostrovsky和Huseyin Yildiz撰写的名为“.Net Matters”的专栏

这篇文章(全部阅读 – 很精彩)展示了内存中并排的值如何最终导致更新时阻塞,因为它们都位于同一缓存行中。 这是非常低级别的阻止,您无法从.Net代码禁用。 但是,您可以强制将数据间隔得更远,以便保证或至少增加每个值将位于不同缓存行上的可能性。

这篇文章使用数组 – 但它可能会影响你。

要跟进下面的建议,您可以通过稍微更改代码来certificate/反驳这一点:

 class Program { class CounterHolder { private int[] fakeInts = new int[1024]; public int Value = 0; } static CounterHolder counter1 = new CounterHolder(); static CounterHolder counter2 = new CounterHolder(); static CounterHolder counter3 = new CounterHolder(); static CounterHolder counter4 = new CounterHolder(); 

然后修改您的线程函数以操作每个计数器持有者的公共字段Value

我让这些arrays真的比他们需要的要大得多,希望它能certificate它更好:)

Andreas Zaltan就是答案。 拿代码

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Diagnostics; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { //static int counter = 0; //static int counter2 = 0; //static int counter3 = 0; //static int counter4 = 0; class CounterHolder { private int[] fakeInts = new int[1024]; public int Value = 0; } static CounterHolder counter1 = new CounterHolder(); static CounterHolder counter2 = new CounterHolder(); static CounterHolder counter3 = new CounterHolder(); static CounterHolder counter4 = new CounterHolder(); static void Main(string[] args) { Console.WriteLine("Without multithreading:"); Console.WriteLine("Start: " + DateTime.Now.ToString()); Stopwatch sw = new Stopwatch(); sw.Start(); countUp(); countUp2(); countUp3(); countUp4(); sw.Stop(); Console.WriteLine("Time taken = " + sw.Elapsed.ToString()); Console.WriteLine("\nWith multithreading:"); Console.WriteLine("Start: " + DateTime.Now.ToString()); sw.Reset(); sw.Start(); Task task1 = Task.Factory.StartNew(() => countUp()); Task task2 = Task.Factory.StartNew(() => countUp2()); Task task3 = Task.Factory.StartNew(() => countUp3()); Task task4 = Task.Factory.StartNew(() => countUp4()); var continuation = Task.Factory.ContinueWhenAll(new[] { task1, task2, task3, task4 }, tasks => { Console.WriteLine("Total Time taken = " + sw.Elapsed.ToString()); }); Console.Read(); } static void countUp() { Stopwatch sw = new Stopwatch(); sw.Start(); for (double i = 0; i < 1000000000; i++) counter1.Value++; sw.Stop(); Console.WriteLine("Task countup took: " + sw.Elapsed.ToString()); } static void countUp2() { Stopwatch sw = new Stopwatch(); sw.Start(); for (double i = 0; i < 1000000000; i++) counter2.Value++; sw.Stop(); Console.WriteLine("Task countUP2 took: " + sw.Elapsed.ToString()); } static void countUp3() { Stopwatch sw = new Stopwatch(); sw.Start(); for (double i = 0; i < 1000000000; i++) counter3.Value++; sw.Stop(); Console.WriteLine("Task countUP2 took: " + sw.Elapsed.ToString()); } static void countUp4() { Stopwatch sw = new Stopwatch(); sw.Start(); for (double i = 0; i < 1000000000; i++) counter4.Value++; sw.Stop(); Console.WriteLine("Task countUP2 took: " + sw.Elapsed.ToString()); } } } 

使用整数运行它,你得到的multithreading版本运行速度稍慢。

 Serial: 13.88s Multi-threaded: 14.01 

使用上面的建议运行它,您将获得以下内容

在此处输入图像描述

为了清楚起见,我发布了这个...

我用StopWatch重写了你的代码。 multithreading比我的计算机上的单线程更快(次数以下)。

此外,您需要在线程上调用方法Join以确保它们在退出程序之前完成。

没有multithreading的时间过去了:00:00:21.6897179

multithreading经过的时间:: 00:00:14.7893703

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Diagnostics; namespace ConsoleApplication1 { class Program { static int counter = 0; static int counter2 = 0; static int counter3 = 0; static int counter4 = 0; static void Main(string[] args) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); countUp(); countUp2(); countUp3(); countUp4(); stopwatch.Stop(); Console.WriteLine("Time elapsed without multithreading:: {0}", stopwatch.Elapsed); stopwatch.Reset(); stopwatch.Start(); Thread thread1 = new Thread(new ThreadStart(countUp)); thread1.Start(); Thread thread2 = new Thread(new ThreadStart(countUp2)); thread2.Start(); Thread thread3 = new Thread(new ThreadStart(countUp3)); thread3.Start(); Thread thread4 = new Thread(new ThreadStart(countUp4)); thread4.Start(); thread1.Join(); thread2.Join(); thread3.Join(); thread4.Join(); stopwatch.Stop(); Console.WriteLine("Time elapsed with multithreading:: {0}", stopwatch.Elapsed); Console.Read(); } static void countUp() { for (double i = 0; i < 1000000000; i++) { counter++; } } static void countUp2() { for (double i = 0; i < 1000000000; i++) { counter2++; } } static void countUp3() { for (double i = 0; i < 1000000000; i++) { counter3++; } } static void countUp4() { for (double i = 0; i < 1000000000; i++) { counter4++; } } } } 

我不是multithreading的专家,但我认为你在那里做的事实上只是将工作从UI线程中移开。

如果您有一些长期或密集的工作要做,这绝不是一件坏事,因为它允许您为最终用户保持响应式UI。 要更快地运行这样的事情,如果我的记忆能够正确地为我服务,你将需要研究并行处理。

首先,使用System.Runtime.Diagnostic命名空间中的StopWatch类进行测量,而不是使用DateTime。

其次,在同步执行后,您不会清除“计数器”。

您应该对所有线程使用并行化,而不是更快! 初始化新线程的成本很高。 顺便说一下,你可以使用ThreadPool。

正如Joeb454所说,在这种情况下你必须寻找并行处理。 您的multithreading只会减慢执行速度,因为创建一个新线程会花费很长时间。