Synchronously waiting for an async operation, and why does Wait() freeze the program here
The await
inside your asynchronous method is trying to come back to the UI thread.
Since the UI thread is busy waiting for the entire task to complete, you have a deadlock.
Moving the async call to Task.Run()
solves the issue.
Because the async call is now running on a thread pool thread, it doesn't try to come back to the UI thread, and everything therefore works.
Alternatively, you could call StartAsTask().ConfigureAwait(false)
before awaiting the inner operation to make it come back to the thread pool rather than the UI thread, avoiding the deadlock entirely.
Trying to call Async method synchronously. It waits on Task.Result forever
This is a classic deadlock. The UI is waiting on the async method to finish, but the async method trys to update the UI thread and BOOM, deadlock.
Curiously though, if I copy this pattern more or less verbatim into a
Console app, it works.
That's because your WinForm application has a custom SynchronizationContext
. It is caputred implicitly and its job is to marshal work back onto the UI thread once returning from your await
.
Should you really expose synchronous wrappers around asynchronous operations?, the answer is no.
There is a way out of it, but i dont really like it. If you absolutely have to (you don't) call your code synchronously (again, you really shouldn't), use ConfigureAwait(false)
inside the async method. This instructs the awaitable
not to capture the current synccontext, so it wont marshal work back onto the UI thread:
public async Task<string> MyMethodAsync()
{
using (var cl = new HttpClient())
{
return await cl.GetStringAsync("http://www.google.co.uk/")
.ConfigureAwait(false);
}
}
Note that if you do this and then try to call any UI element afterwards, you'll end up with an InvalidOperationException
since you won't be on the UI thread.
Initializing the UI via a constructor is a common pattern. Stephan Cleary has a very nice series on async which you can find here.
What am I doing wrong? Is this simply a bad pattern, and if so, what
pattern should I be using instead?
Yes, absolutely. If you want to expose both asynchronous and synchronous APIs, use the proper api's which wouldn't get you into this situation (a deadlock) in the firstcase. For example, if you want to expose a synchronous DownloadString
, use WebClient
instead.
Calling async function in synchronous function doesn't wait for it to finish
Following Panagiotis Kanavos's advice:
Tasks aren't threads. There's no good reason to call Task.Start in
application code. How is checkInstalled called? That method should be
asynchronous itself, going all the way to the top-level event handler
that started these calls. The event handler should be async void but
all the other methods should be async Task. Calling .Wait() will
freeze the UI
After making every necessary function async and using await when needed I managed to get everything working the way I wanted
Windows Store Application - Synchronously waiting for an async operation
This is not a solution for doing anything synchronously, it's simply how to avoid calling back to the UI thread when you don't need to. The problem with your actual code is that you've defined an extension for IAsyncOperation<T>
, not IAsyncAction
.
Asynchronously wait for Task T to complete with timeout
How about this:
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
And here's a great blog post "Crafting a Task.TimeoutAfter Method" (from MS Parallel Library team) with more info on this sort of thing.
Addition: at the request of a comment on my answer, here is an expanded solution that includes cancellation handling. Note that passing cancellation to the task and the timer means that there are multiple ways cancellation can be experienced in your code, and you should be sure to test for and be confident you properly handle all of them. Don't leave to chance various combinations and hope your computer does the right thing at runtime.
int timeout = 1000;
var task = SomeOperationAsync(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
}
else
{
// timeout/cancellation logic
}
Related Topics
Hyphenated HTML Attributes with ASP.NET MVC
A Property or Indexer May Not Be Passed as an Out or Ref Parameter
Avoiding First Chance Exception Messages When the Exception Is Safely Handled
Converting Bitmap Pixelformats in C#
Properties VS. Fields: Need Help Grasping the Uses of Properties Over Fields
How to Combine More Than Two Generic Lists in C# Zip
Convert a Binary String Representation to a Byte Array
Viewmodels in MVC/Mvvm/Separation of Layers- Best Practices
Finding an Enum Value by Its Description Attribute
Error - Unable to Access the Iis Metabase
The Type or Namespace Name Does Not Exist in the Namespace 'System.Web.Mvc'
Escape Command Line Arguments in C#
Splitting a String/Number Every Nth Character/Number
Property(With No Extra Processing) VS Public Field
The Need for Volatile Modifier in Double Checked Locking in .Net