abhi
abhi

Reputation: 3136

Multithreading and speeding things up

I have the following piece of code. I wish to start the file creation on multiple threads. The objective is that it will take less time to create 10 files when I do it on multiple threads. As I understand I need to introduce the element of asynchronous calls to make that happen.

What changes should I make in this piece of code?

using System;
using System.Text;
using System.Threading;
using System.IO;
using System.Diagnostics;

namespace MultiDemo
{
    class MultiDemo
    {
        public static void Main()
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
            // Create an instance of the test class.
            var ad = new MultiDemo();

            //Should create 10 files in a loop.
            for (var x = 0; x < 10; x++)
            {
                var y = x;
                int threadId;
                var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
                myThread.Start();
                myThread.Join();
                //TestMethod("outpFile", y, out threadId);
            }
            stopWatch.Stop();
            Console.WriteLine("Seconds Taken:\t{0}",stopWatch.Elapsed.TotalMilliseconds);
        }

        public static void TestMethod(string fileName, int hifi, out int threadId)
        {
            fileName = fileName + hifi;
            var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            var sw = new StreamWriter(fs, Encoding.UTF8);
            for (int x = 0; x < 10000; x++)
                {
                    sw.WriteLine(DateTime.Now.ToString());
                }
            sw.Close();
           threadId = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("{0}",threadId);
        }
    }
}

Right now, if I comment the thread creation part of the code and just call testMethod 10 times in a loop, it is faster than the multiple threads that the thread creation attempts to process.

Upvotes: 1

Views: 158

Answers (8)

Boppity Bop
Boppity Bop

Reputation: 10463

try something like:

for (int i = 0; i < 10; ++i)  
{ 
   new Action(() => { TestMethod("outpFile"); }).BeginInvoke(null,null); 
}
Console.ReadLine();

if it wont be quicker than serial calls then indeed your IO is a botleneck and nothing you can do about it.

Upvotes: 0

Sam Harwell
Sam Harwell

Reputation: 99869

The primary thing to observe in your case is Amdahl's Law. Your algorithm makes roughly equal use of each of the following resources:

  1. Processor usage
  2. Memory access
  3. Drive access

Of these, the drive access is by far the slowest item, so to see speedup you'll need to parallelize your algorithm across this resource. In other words, if you parallelize your program by writing the 10 different files to 10 different drives, you'll see a substantial performance improvement compared to just parallelizing the computation of the file contents. In fact if you create the files on 10 different threads, the serialization involved with drive access could actually reduce the overall performance of your program.

Although both imply multi-threaded programming, parallelization should NOT be treated the same as asynchronous programming in the case of IO. While I would not recommend parallelizing your use of the file system, it is almost always beneficial to use asynchronous methods for reading/writing to files.

Upvotes: 1

Austin Salonen
Austin Salonen

Reputation: 50225

The reason you're slower is that all you're doing is starting up a new thread and waiting for it to complete so it has to be slower because your other method is simply not doing 3 steps.

Try this out (assuming .Net 4.0 because of TPL). On my machine, it's consistently 100ms faster when done in parallel.

[Test]
public void Y()
{
    var sw = Stopwatch.StartNew();
    Parallel.For(0, 10, n => TestMethod("parallel", n));

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);

    sw.Restart();

    for (int i = 0; i < 10; i++)
        TestMethod("forloop", i);

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}


private static void TestMethod(string fileName, int hifi)
{
    fileName = fileName + hifi;
    var fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    var sw = new StreamWriter(fs, Encoding.UTF8);
    for (int x = 0; x < 10000; x++)
    {
        sw.WriteLine(DateTime.Now.ToString());
    }
    sw.Close();
}

Upvotes: 1

Ed Power
Ed Power

Reputation: 8531

You're negating the benefit of multiple threads because you Join each thread and thus wait for it to complete before you create and start the next thread.

Instead, add the threads to a list as you create and start them, and then loop through the list of threads, joining them in sequence until they finish.

using System.Collections.Generic;
List<Thread> threads= new List<Thread>();
//Should create 10 files in a loop.
for (var x = 0; x < 10; x++)
{
    var y = x;
    int threadId;
    var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
    threads.Add(myThread);
    myThread.Start();
    //myThread.Join();
    //TestMethod("outpFile", y, out threadId);
}
foreach (var thread in threads) thread.Join();

Upvotes: 0

Nate Kohl
Nate Kohl

Reputation: 35914

The threaded version of your code is doing extra work, so it's not suprising that it's slower.

When you do something like:

var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
myThread.Start();
myThread.Join();

...you're creating a thread, having it call TestMethod, then waiting for it to finish. The additional overhead of creating and starting a thread will make things slower than just calling TestMethod without any threads.

It's possible that you'll see better performance if you start all of the threads working and then wait for them to finish, e.g.:

var workers = new List<Thread>();
for (int i = 0; i < 10; ++i) 
{
   var y = x;
   int threadId;
   var myThread = new Thread(() => TestMethod("outpFile", y, out threadId));
   myThread.Start();
   workers.Add(myThread);
}
foreach (var worker in workers) worker.Join();

Upvotes: 5

YavgenyP
YavgenyP

Reputation: 2123

So why did you decide to use multi threading? The price of starting a new thread might be higher than a simple loop. Its not something you can blindly decide about... If you insist on using threads, you can also check the managed ThreadPool / usage of async delegates, which can reduce the cost of creating new threads, by re-using existing ones.

Upvotes: 0

Kevin Aenmey
Kevin Aenmey

Reputation: 13419

Perhaps this doesn't directly answer your question but here is my thought on the matter. The bottleneck in that code is unlikely to be the processor. I would bet the disk IO would take way more time than the CPU processing. As such, I don't believe that creating new threads will help at all (all the threads will attempt to write to the same disk). I think this is a case of premature optimization. If I were you, I would just do it all on one thread.

Upvotes: 1

burning_LEGION
burning_LEGION

Reputation: 13450

it's wrong way to get up speed, multithreading for parallel work, but not for accelerate

Upvotes: 0

Related Questions