为什么我的多线程比单线程慢?

时间:2015-04-30 06:24:17

标签: c# multithreading

我知道有几个人问了类似这样的问题,但我找不到任何可以让我理解为什么它变慢的回复。

因此,我为自己对Visual Studio 2013中的线程对象的理解制作了一个小程序控制台程序。我的CPU是Intel Core i7,供应可以使用多个线程。

我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {

        static TimeSpan MTTime;
        static TimeSpan STTime;

        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();


            Console.WriteLine(Environment.NewLine + "---------------Multi Process-------------" + Environment.NewLine);

            Thread th1 = new Thread(new ParameterizedThreadStart(Process));
            Thread th2 = new Thread(new ParameterizedThreadStart(Process));
            Thread th3 = new Thread(new ParameterizedThreadStart(Process));
            Thread th4 = new Thread(new ParameterizedThreadStart(Process));

            th1.Start("A");
            th2.Start("B");
            th3.Start("C");
            th4.Start("D");

            th1.Join();
            th2.Join();
            th3.Join();
            th4.Join();

            stopwatch.Stop();
            MTTime = stopwatch.Elapsed ;

            Console.WriteLine(Environment.NewLine + "---------------Single Process-------------" + Environment.NewLine);


            stopwatch.Reset();
            stopwatch.Start();

            Process("A");
            Process("B");
            Process("C");
            Process("D");

            stopwatch.Stop();
            STTime = stopwatch.Elapsed;

            Console.Write(Environment.NewLine + Environment.NewLine + "Multi  : "+ MTTime + Environment.NewLine + "Single : " + STTime);


            Console.ReadKey();
        }

        static void Process(object procName)
        {
            for (int i = 0; i < 100; i++)
            {
                Console.Write(procName);
            }
        }
    }
}

结果图片:

enter image description here

我们可以清楚地看到多踩踏过程是完全随机的,而单个踩踏过程只是按下另一个,但我不认为这会对速度产生影响。

起初,我认为我的线程比运行程序所需的过程要大,但是在更换一个更大的进程之后,单步行仍然是最快的。那么,我是否会错过多线程的概念?还是正常的那么慢?

6 个答案:

答案 0 :(得分:72)

请注意Process写入控制台(基本上什么都不做),并且输出到控制台(这里作为一种共享资源)很慢,需要与其他线程同步

据我了解,您使用的并行化会产生巨大的开销,但不会加速,因为线程显然主要是等待其他进程完成写入控制台。

答案 1 :(得分:44)

来自官方Console文档

  

使用这些流的I / O操作是同步的,这意味着   多个线程可以读取或写入流。这个   表示通常异步的方法,例如   TextReader.ReadLineAsync,如果对象同步执行   表示控制台流

这意味着控制台类处理线程同步,因此如果线程A和线程B正在尝试写入控制台,控制台将处理它们,并且只有一个时间能够写入。它背后的 处理逻辑 是需要更长时间的原因


更新
我建议你看一下Parallel.ForEach

答案 2 :(得分:4)

还要考虑的另一件事是:您正在遭受线程创建和加入的开销。此外,您可以通过使用线程池进行轻微的性能升级,请看一下:

https://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem%28v=vs.110%29.aspx

答案 3 :(得分:4)

OK!对阿萨和科多来说,把我的想法放在了正确的位置!我最终制作了一个小的控制台程序,显示每个人非常苛刻。使用重型处理时,最终多线程速度更快。只需阅读我的代码,你就会轻松理解。

结果:

enter image description here

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        //Timer for speed guidance
        static Stopwatch stopwatch;
        //Data i use for generate time
        static List<int> timeData;
        static void Main(string[] args)
        {
            stopwatch = new Stopwatch();
            timeData = new List<int> { 1000, 800, 200, 700, 600, 300, 800, 100, 200, 300, 655, 856, 695, 425 };

            ////-------------------------- SINGLE THREAD ------------------------------/////
            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("             Single Threading Process            ");
            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("   Process Time        Thread ID                 ");
            Console.WriteLine("-------------------------------------------------");
            stopwatch.Reset();
            stopwatch.Start();
            //For each normal that use only 1 thread
            foreach(int i in timeData)
            {
                Process(i);
            }

            stopwatch.Stop();
            //Total time that the program take for making the process happen
            Console.WriteLine("*Total : " + stopwatch.Elapsed );

            ////-------------------------- Mulit Multiple ------------------------------/////

            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("             Multi Threading Process            ");
            Console.WriteLine("-------------------------------------------------");
            Console.WriteLine("   Process Time        Thread ID                 ");
            Console.WriteLine("-------------------------------------------------");
            stopwatch.Reset();
            stopwatch.Start();
            //for each thats use Multiple thread fr the process (can be made with parallel.invoke or Task Library or Thread Library)
            Parallel.ForEach(timeData, (i) => Process(i));
            //Total time that the program take for making the process happen
            Console.WriteLine("*Total : " + stopwatch.Elapsed);
            Console.WriteLine("-------------------------------------------------");
            Console.ReadKey();
        }

        // Methode for sumulating long processing
        static void Process( int time)
        {
            stopwatch.Reset();
            stopwatch.Start();
            //sleep time simulate the IO portion of the process
            Thread.Sleep(time);
            // The loop simulate de algoritme type of precessing
            for (int i = 0; i < time*1000000; i++){}
            stopwatch.Stop();
            Console.WriteLine( stopwatch.Elapsed + "         " + Thread.CurrentThread.ManagedThreadId.ToString());          
        }


    }
}

答案 4 :(得分:0)

当且仅当处理器是瓶颈时,应用程序将更快地使用多个线程。有时您的磁盘或RAM是瓶颈。通常它是数据库或外部服务。在这些情况下,添加多个线程不太可能使代码运行得更快,相反,由于额外的同步,它通常会降低执行速度。

如果您想让代码运行得更快,首先必须检查是什么让它运行缓慢。 描述您的代码。找到瓶颈

请记住Premature optimization is the root of all evil

在您的情况下,瓶颈 - 阻止所有操作的单个访问最多的资源 - 是控制台输出流。它有一个单一的实例,它的工作相对较慢。即使单个核心也不会100%使用,以尽快打印。

答案 5 :(得分:-1)

如果您删除下面的行,您的多线程会更快。

Console.Write(procName);

因为操作系统将Console视为共享资源,并且只有一个线程可以立即使用共享资源。因此,在这种情况下,mutlithread加速将像一个单独的线程,但多线程会增加一些额外的线程管理开销没有性能提升。