1

I was just doing some tests on sync vs async and wrote following program to test. Maybe I have done something wrong or I just don't get/understand async correctly,

I see my sync version takes 318 ms while async takes 18764 ms

static void Main(string[] args)
        {
            int num = 25;
            Task[] tasks = new Task[num];

            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < num; i++)
            {
                int c = i;
                tasks[i] = Task.Factory.StartNew(() => { RunAsync(c).Wait(); });
            }
            Task.WaitAll(tasks);
            sw.Stop();
            Console.WriteLine($"FINISHED (Async) in {sw.ElapsedMilliseconds} ms");

            sw.Start();
            for (int i = 0; i < num; i++)
            {
                RunSync(i + 100);
            }
            sw.Stop();
            Console.WriteLine($"FINISHED (Sync) in {sw.ElapsedMilliseconds} ms");

            Console.ReadLine();
        }

        private static void RunSync(int index)
        {
            FileStream stream = new FileStream(@"c:\\test\ff\tests.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
            string pp = Path.Combine(@"c:\\test\ff", "threadS-" + index + ".txt");
            FileStream sw = File.Create(pp);
            byte[] buffer = new byte[1024];
            long bytesRead = 0;
            long bytestoRead = stream.Length;
            try
            {
                while (bytesRead < bytestoRead)
                {
                    int count = stream.Read(buffer, 0, buffer.Length);
                    bytesRead += count;
                    sw.Write(buffer, 0, count);
                }
            }
            finally
            {
                sw.Close();
                stream.Close();
            }
        }

        private async static Task RunAsync(int index)
        {
            FileStream stream = new FileStream(@"c:\\test\ff\tests.txt", FileMode.Open, FileAccess.Read, FileShare.Read);
            int tId = Thread.CurrentThread.ManagedThreadId;

            string pp = Path.Combine(@"c:\\test\ff", "thread-" + index + ".txt");
            FileStream sw = File.Create(pp);
            byte[] buffer = new byte[1024];
            long bytesRead = 0;
            long bytestoRead = stream.Length;
            try
            {
                while (bytesRead < bytestoRead)
                {
                    int count = await stream.ReadAsync(buffer, 0, buffer.Length);
                    bytesRead += count;
                    await sw.WriteAsync(buffer, 0, count);
                }
            }
            finally
            {
                sw.Close();
                stream.Close();
            }
        }
Embedd_0913
  • 16,125
  • 37
  • 97
  • 135
  • 1
    Also http://stackoverflow.com/questions/27189082/async-await-makes-my-tasks-slow-while-task-start-runs-them-fast – trailmax Apr 26 '16 at 14:24
  • 1
    And http://stackoverflow.com/a/15666011/809357 – trailmax Apr 26 '16 at 14:25
  • 1
    And a good explanation why use async http://stackoverflow.com/a/15665968/809357 – trailmax Apr 26 '16 at 14:26
  • 1
    Impressive collection of links @trailmax. Well done :P – David L Apr 26 '16 at 14:26
  • @DavidL Knowing the answer, I stackoverflowed.. er googled it -) – trailmax Apr 26 '16 at 14:27
  • You can't really do IO in parallel, even with solid state drives you lose performance. You have 25 different threads telling the drive to write to 25 non-sequential locations; it's not going to fare any better than you would having to put laundry away for 25 different people who live in different rooms and you can only put 1 article of clothing away before having to move randomly to another room. You have 25 threads that can do *computation* at the same time, but you only have 1 hard drive that can *write data*. – Quantic Apr 26 '16 at 14:42

2 Answers2

2

There are a couple things you are doing incorrectly, and a false premise you are starting with. So let me start with the false premise:

async / await are designed to keep an app responsive or distribute work among many cores--they don't necessarily improve run-time performance.

In other words, when you look at overall throughput, you might handle more work than processing a unit of work serially. However, that threshold is going to vary on the amount of work being done at any given time.

Handling async / await properly means not mixing older Task functions with the newer support. That loses all the benefits of the async functions and adds to the synchronization overhead. Never call Task.Wait() or Task.WaitAll(tasks) when you want to wait for the background work to be done. That forces the one thread to be completely paused and unresponsive until background work is done.

You want to make the following adjustments:

        for (int i = 0; i < num; i++)
        {
            int c = i;
            tasks[i] = RunAsync(c);
        }
        await Task.WhenAll(tasks);

Since you can't make your Main function be async, you might have to move that call to another function so you can do the async/await protocol.

Berin Loritsch
  • 11,400
  • 4
  • 30
  • 57
1

asynchronous calls do not necessarily have a guaranteed time of execution. They'll be called as the scheduler decides resources are available. Because of this, the wait time for them to be completed may be higher than calling the same method synchronously as synchronous calls are guaranteed to be executed at the moment of being called, in realtime.

Chris M
  • 11
  • 3