amergan
amergan

Reputation: 307

C# async await weird behavior

I'm new to C# and for now I'm trying to understand async/await feautures. So I have created small sandbox app:

namespace sandbox
{
public class Test
{
    public async Task<string> GetItemsAsync()
    {
        var a = await Task1();
        var b = await Task2();
        var c = await Task3();

        return a + b + c;
    }

    public string GetItems()
    {
        return _T1() + _T2() + _T3();
    }

    private readonly int cycles = 100000000;

    private async Task<string> Task1()
    {
        return await Task.Factory.StartNew(_T1);
    }

    private async Task<string> Task2()
    {
        return await Task.Factory.StartNew(_T2);
    }

    private async Task<string> Task3()
    {
        return await Task.Factory.StartNew(_T3);
    }

    // long running operation
    private string _T1()
    {
        for (int i = 0; i < cycles; i++) ;
        for (int i = 0; i < cycles; i++) ;
        return "One";
    }

    // long running operation
    private string _T2()
    {
        for (int i = 0; i < cycles; i++) ;
        for (int i = 0; i < cycles; i++) ;
        return "Two";
    }

    // long running operation
    private string _T3()
    {
        for (int i = 0; i < cycles; i++) ;
        for (int i = 0; i < cycles; i++) ;
        return "Three";
    }
}

class Program
{
    static void Main(string[] args)
    {
        var t = new Test();

        Console.WriteLine("Async");
        Stopwatch sw = new Stopwatch();
        sw.Start();
        var result = t.GetItemsAsync();
        Console.WriteLine(result.Result);
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        Console.WriteLine("Sync");
        sw.Restart();
        var strResult = t.GetItems();
        Console.WriteLine(strResult);
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        Console.ReadLine();
    }
}
}

But the result is weird:

Async
OneTwoThree
1754
Sync
OneTwoThree
1506

Async method runs longer than similar sync one. For me it's look like async methods runs synchronously but I cant figure out why.

Upvotes: 0

Views: 426

Answers (2)

Volodymyr Dombrovskyi
Volodymyr Dombrovskyi

Reputation: 269

I suspect the intention was to make all three tasks do the job in parallel. That is one of options how it could be accomplished:

public async Task<string> GetItemsAsync()
{
    var a = Task1();
    var b = Task2();
    var c = Task3();

    return string.Concat(await Task.WhenAll(a, b, c));
}

Upvotes: 1

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391664

Because of this:

var a = await Task1();
var b = await Task2();
var c = await Task3();

Before you even start Task2 you have waited for Task1 to complete. So you're not running them in parallel, you're running them in sequence.

If you want to start all 3 tasks, then wait for them to complete you would have to change this method to this:

public async Task<string> GetItemsAsync()
{
    var t1 = Task1();
    var t2 = Task2();
    var t3 = Task3();

    var a = await t1;
    var b = await t2;
    var c = await t3;

    return a + b + c;
}

Or just the last part:

return (await t1) + (await t2) + (await t3);

Additionally, this code is an antipattern:

private async Task<string> Task3()
{
    return await Task.Factory.StartNew(_T3);
}

You don't need async/await here because you're not doing any more work in this method after your sub-task returns.

Instead simply rewrite this method (and its siblings) to this:

private Task<string> Task3()
{
    return Task.Factory.StartNew(_T3);
}

Upvotes: 4

Related Questions