4

Not sure if I am messed up with my understanding of how async await works, but here is the problem I am stucked at. Consider a contrived example

  1. This code blocks UI

    public async void LoginButtonClicked()
    {
     //create a continuation point so every following statement will get executed as ContinueWith
     await Task.FromResult(0);
     //this call takes time to execute
     Remote.Login("user","password");
    }
    
  2. But this does not (obviously)

     public void LoginButtonClicked()
     {
     Task.Run(()=>{ Remote.Login("user","password");});
      }
    

I like to use method 1 because I don't want to spin long work using a Task.Run rather I prefer framework handle this form me. But the problem is The call to Method 1 seems blocking.

3
  • 1
    await only does anything fancy if the thing to it's right has not completed. a Task.FromResult always returns a completed task, and so the method continues merrily on its way past that await point. Commented Jan 10, 2014 at 7:34
  • 1
    And this old Eric Lippert blog post might help: "The whole point of async methods it that you stay on the current thread as much as possible." Commented Jan 10, 2014 at 7:39
  • Task.FromResult should not be called with await: Should I await on Task.FromResult Method Calls? Commented Mar 9, 2019 at 12:40

3 Answers 3

5

Using await/async only stops you from blocking the UI if all the long-running operations you call are async. In your example your Remote.Login is a synchronous call, so regardless of what the prior await line does, this will block your UI.

You need to either get an async version of your actual long-running operation (eg something returning a Task) or if that is not possible, then you can resort to Task.Run in order to move this work to the ThreadPool.

What you want if possible:

public async void LoginButtonClicked()
{
    await Remote.LoginAsync("user","password");
    // do anything else required
}
Sign up to request clarification or add additional context in comments.

Comments

2

Every async method has its context.

When the Task starts it might run in a new SynchronizationContext. "Might" because if the task is already completed, like Task.FromResult(0), then no other SynchronizationContext is created and the original one is used.

Awaiting for a task means that when the task is finished, the next statement will run in the original SynchronizationContext.

This behavior can be changed using the Task.ConfigureAwait(continueOnCapturedContext: false). This means that the next statement will continue on the same context. But this will change nothing by doing Task.FromResult(0).ConfigureAwait(false) because the task is already completed and the original context will be used.

Therefore your Remote.Login("user","password"); will be run in the original context, thus blocking the UI thread which runs on the same context.

If you would have something like:

public async void LoginButtonClicked()
{
  await Task.Delay(5000).ConfigureAwait(false);
  Remote.Login("user","password");
}

Then Remote.Login("user","password"); would execute in the thread pool context thus being on a different context than the original UI context.

So the best way to fix your code is to create a Remote.LoginAsync() as stated in @Nicholas W answer.

NOTE on performance: if you have an async method with multiple await statements, and you don't need some of those awaits to do work on UI or web app thread, then you can use Task.ConfigureAwait(false) in order to prevent multiple switches to the UI/web-app context which slices its execution time.

Comments

-2
  1. You run in parallel Task.FromResult(0); and still wait for Remote.Login("user","password"); to be finished
  2. You run Remote.Login("user","password"); asynchronously.

You have to create async version of Remote.Login

    async Task LoginAsync(string user, string password)
    {
        Remote.Login(user, password);
        await Task.FromResult(0);
    }

and call it

    public async void LoginButtonClicked()
    {
        await LoginAsync("user", "password");
    }

1 Comment

That's a synchronous method, not an asynchronous method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.