user3691221
user3691221

Reputation: 109

async Controller with async Action doesn't work

I have async controller with async action. In the action I call WCF service method in SomeMethodOne (it needs 10 seconds to return result) and then I execute some mathematical operations in SomeMethodTwo (it executes about 6 seconds on my computer). As I understand during waiting on result from WCF service method, my computer should execute SomeMethodTwo but it doesn't and all code executes 10 seconds + 6 seconds = 16 seconds. Why?

public class TestController : AsyncController
{
    public async Task<ActionResult> Index()
    {
        string result =  await SomeMethodOne();

        SomeMethodTwo();

        return View();
    }

    private async Task<string> SomeMethodOne() // it needs 10 seconds to return result from WCF service
    {
        using (Service1Client client = new Service1Client())
        {
            return await client.GetDataAsync(5);
        }
    }

    private void SomeMethodTwo() // it executes about 6 seconds on my computer
    {
        double result = 0;
        for (int i = 0; i < 1000000000; i++)
        {
            result += Math.Sqrt(i);
        }
    }
}

The WCF service which I run locally:

public class Service1 : IService1
{
    public string GetData(int value)
    {
        Thread.Sleep(10000);
        return string.Format("You entered: {0}", value);
    }        
}

Upvotes: 1

Views: 1178

Answers (2)

Jon Hanna
Jon Hanna

Reputation: 113342

and then I execute [emphasis mine]

Doing one thing and then doing another thing will take as long as both of them added together.

Doing two things at the same time might be quicker. It might be slower, because of context switching (imagine someone doing lots of "multitasking" and spending more time switching between them than working). It's likely it will be quicker here, if you don't have to get the results from the first action in order to do the second:

public async Task<ActionResult> Index()
{
    Task<string> task =  SomeMethodOne();

    SomeMethodTwo();

    string result = await task;

    return View();
}

Obviously if you needed result before you could call SomeMethodTwo() then this wouldn't be possible. There is still an advantage on awaiting SomeMethodOne() (which should be called SomeMethodOneAsync() if possible to fit with .NET conventions), in that if GetDataAsync() is truly async then the thread that was executing this action method can do something else for some other request to your web application, and another thread will pick up on dealing with this one when the I/O operation has returned data. This doesn't help the performance of the single method involved, but does help overall scalability of all the methods being run on the machine for all the web requests.

Upvotes: 1

Stephen Cleary
Stephen Cleary

Reputation: 457057

Your problem is that you're using await right away:

string result =  await SomeMethodOne();

The await means that your controller action is going to "asynchronously wait" (await) for the result of SomeMethodOne before it continues executing.

If you want to do asynchronous concurrency, then don't await right away. Instead, you can start the asynchronous operation going by calling the method and then await later:

public async Task<ActionResult> Index()
{
  Task<string> firstOperation = SomeMethodOne();

  SomeMethodTwo();

  string result = await firstOperation;

  return View();
}

Upvotes: 3

Related Questions