Kazimar
Kazimar

Reputation: 375

Why is my multi-threading slower than my single threading?

I know a couple of people asked a question similar to this, but I can’t find any response that would make me understand why it's slower.

So, I made a little console program for my own understanding of the threading object in Visual Studio 2013. My CPU is an Intel Core i7 that supply can use multiple threading.

My code:

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);
            }
        }
    }
}

Result image:

enter image description here

We can clearly see that the multi-treading process is total random and the single one just do all presses on after the other, but I don't think this have an impact on the speed.

At first, I thought my thread was just bigger than the process needed for running the program, but after changing for a bigger process the single treading still was still the fastest in a big way. So, do i miss a concept in multi-threading? Or it normal that is slower?

Upvotes: 31

Views: 17082

Answers (6)

Dariusz
Dariusz

Reputation: 22241

Applications will work faster with multiple threads if and only if the processor is a bottleneck. Sometimes your disk or RAM are bottlenecks. Most often it's a database or an external service. Adding multiple threads isn't likely to make the code run faster in those cases, quite the contrary, it will often slow execution due to additional synchronization.

If you want to make your code run faster, you must first check what makes it run slowly. Profile your code. Locate the bottleneck.

And remember that Premature optimization is the root of all evil

In your case the bottleneck - the single most-accessed resource which blocks all actions - is the console output stream. It has a single instance and it works relatively slowly. Even a single core won't be used 100% to print on it as fast as possible.

Upvotes: 0

AmirHossein Rezaei
AmirHossein Rezaei

Reputation: 1400

If you delete line below, your multithread would be faster.

Console.Write(procName);

its because the operating system treat Console as a shared resource and just one thread can use a shared resource at a moment.So in this condition, mutlithread speed up would be like a single thread, but multithreading is burdening some additional thread management overhead with no performance gain.

Upvotes: 0

Codor
Codor

Reputation: 17595

Note that Process writes to the console (and basically does nothing else), and that output to the console (which here acts as a kind of shared resource) is slow and needs to be synchronized with the other threads.

To my understanding, the parallelization you use creates a huge overhead but gains no speedup, because all of the time the threads are apparently mostly waiting for the other process to finish writing to the console.

Upvotes: 71

Kazimar
Kazimar

Reputation: 375

OK! thx to Assa and Codor to put my mind to the right place! I finaly make a little console programe that show everyting very clairly. Finaly multitreading is a LOT faster when using heavy processing stuff . Just read my code and u gonna understand with ease.

Result :

enter image description here

Code :

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());          
        }


    }
}

Upvotes: 4

VidasV
VidasV

Reputation: 4895

One more thing to take into account: you are suffering from overhead for thread creation and join. Also, you might get a slight performance upgrade by using threadpool, take a look here:

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

Upvotes: 4

Sid
Sid

Reputation: 14896

From the official Console documentation

I/O operations that use these streams are synchronized, which means that multiple threads can read from, or write to, the streams. This means that methods that are ordinarily asynchronous, such as TextReader.ReadLineAsync, execute synchronously if the object represents a console stream

This means that the console class handles the thread synchronization so if thread A and thread B are trying to write to the console the console will handle them and only one for time will be able to write. The handling logic behind it is the reason why it takes longer


UPDATE
I suggest you to have a look at Parallel.ForEach

Upvotes: 44

Related Questions