I'm new to c# async await mechanism. I read some articles about async all the way (http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). I have an example below, could you please let me know if the first Initialize method will cause dead lock and why? Thank you in advance.
public class Test {
public async Task DoSomeWorkAsync() {
await DoSomeWork1Async();
}
// This method is mixed with Wait and async await, will this cause lead lock?
public void Initialize() {
Task.Run(() => DoSomeWorkAsync()).Wait();
}
// This method is following async all the way
public async Task InitializeAsync() {
await DoSomeWorkAsync();
}
}
// Update: Here is the context where two Initialize methods are called
public class TestForm : Form {
// Load Form UI
public async void OnLoad() {
var test = new Test();
test.Initialize();
await test.InitializeAsync();
}
}
No, this will not deadlock because you're blocking on a task that's being executed by a ThreadPool thread with no SynchronizationContext. Since it isn't running on the UI thread there's nothing stopping that task from completing and so there's no deadlock.
If this was your code, it will have deadlocked:
public void Initialize()
{
DoSomeWorkAsync().Wait();
}
This is still not a good reason to block though, you should use async-await all they way up.
Related
I have the following four tests and the last one hangs when I run it. Why does this happen:
[Test]
public void CheckOnceResultTest()
{
Assert.IsTrue(CheckStatus().Result);
}
[Test]
public async void CheckOnceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceResultTest()
{
Assert.IsTrue(CheckStatus().Result); // This hangs
Assert.IsTrue(await CheckStatus());
}
private async Task<bool> CheckStatus()
{
var restClient = new RestClient(#"https://api.test.nordnet.se/next/1");
Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
IRestResponse<DummyServiceStatus> response = await restResponse;
return response.Data.SystemRunning;
}
I use this extension method for restsharp RestClient:
public static class RestClientExt
{
public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
{
var tcs = new TaskCompletionSource<IRestResponse<T>>();
RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
return tcs.Task;
}
}
public class DummyServiceStatus
{
public string Message { get; set; }
public bool ValidVersion { get; set; }
public bool SystemRunning { get; set; }
public bool SkipPhrase { get; set; }
public long Timestamp { get; set; }
}
Why does the last test hang?
Acquiring a value via an async method:
var result = Task.Run(() => asyncGetValue()).Result;
Syncronously calling an async method
Task.Run( () => asyncMethod()).Wait();
No deadlock issues will occur due to the use of Task.Run.
You're running into the standard deadlock situation that I describe on my blog and in an MSDN article: the async method is attempting to schedule its continuation onto a thread that is being blocked by the call to Result.
In this case, your SynchronizationContext is the one used by NUnit to execute async void test methods. I would try using async Task test methods instead.
You can avoid deadlock adding ConfigureAwait(false) to this line:
IRestResponse<DummyServiceStatus> response = await restResponse;
=>
IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);
I've described this pitfall in my blog post Pitfalls of async/await
You are blocking the UI by using Task.Result property.
In MSDN Documentation they have clearly mentioned that,
"The Result property is a blocking property. If you try to access it
before its task is finished, the thread that's currently active is
blocked until the task completes and the value is available. In most
cases, you should access the value by using Await or await instead of
accessing the property directly."
The best solution for this scenario would be to remove both await & async from methods & use only Task where you're returning result. It won't mess your execution sequence.
An addition to the answer given by #HermanSchoenfeld. Unfortunately the quote below is not true:
No deadlock issues will occur due to the use of Task.Run.
public String GetSqlConnString(RubrikkUser user, RubrikkDb db)
{
// deadlock if called from threadpool,
// works fine on UI thread, works fine from console main
return Task.Run(() =>
GetSqlConnStringAsync(user, db)).Result;
}
The execution is wrapped inside a Task.Run, this will schedule the task on the threadpool the block the calling thread. This is okay, as long as the calling thread is not a threadpool thread. If the calling thread is from the threadpool then the following disaster happens: A new task is queued to the end of the queue, and the threadpool thread which would eventually execute the Task is blocked until the Task is executed.
In library code there is no easy solution as you cannot assume under what context your code is called. The best solution is to only call async code from async code, blocking sync APIs from sync methods, don’t mix them.
Source:
https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d
If you don't get any callbacks or the control hangs up, after calling the service/API async function, you have to configure Context to return a result on the same called context.
Use TestAsync().ConfigureAwait(continueOnCapturedContext: false);
You will be facing this issue only in web applications, but not in static void main.
I have the following four tests and the last one hangs when I run it. Why does this happen:
[Test]
public void CheckOnceResultTest()
{
Assert.IsTrue(CheckStatus().Result);
}
[Test]
public async void CheckOnceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceAwaitTest()
{
Assert.IsTrue(await CheckStatus());
Assert.IsTrue(await CheckStatus());
}
[Test]
public async void CheckStatusTwiceResultTest()
{
Assert.IsTrue(CheckStatus().Result); // This hangs
Assert.IsTrue(await CheckStatus());
}
private async Task<bool> CheckStatus()
{
var restClient = new RestClient(#"https://api.test.nordnet.se/next/1");
Task<IRestResponse<DummyServiceStatus>> restResponse = restClient.ExecuteTaskAsync<DummyServiceStatus>(new RestRequest(Method.GET));
IRestResponse<DummyServiceStatus> response = await restResponse;
return response.Data.SystemRunning;
}
I use this extension method for restsharp RestClient:
public static class RestClientExt
{
public static Task<IRestResponse<T>> ExecuteTaskAsync<T>(this RestClient client, IRestRequest request) where T : new()
{
var tcs = new TaskCompletionSource<IRestResponse<T>>();
RestRequestAsyncHandle asyncHandle = client.ExecuteAsync<T>(request, tcs.SetResult);
return tcs.Task;
}
}
public class DummyServiceStatus
{
public string Message { get; set; }
public bool ValidVersion { get; set; }
public bool SystemRunning { get; set; }
public bool SkipPhrase { get; set; }
public long Timestamp { get; set; }
}
Why does the last test hang?
Acquiring a value via an async method:
var result = Task.Run(() => asyncGetValue()).Result;
Syncronously calling an async method
Task.Run( () => asyncMethod()).Wait();
No deadlock issues will occur due to the use of Task.Run.
You're running into the standard deadlock situation that I describe on my blog and in an MSDN article: the async method is attempting to schedule its continuation onto a thread that is being blocked by the call to Result.
In this case, your SynchronizationContext is the one used by NUnit to execute async void test methods. I would try using async Task test methods instead.
You can avoid deadlock adding ConfigureAwait(false) to this line:
IRestResponse<DummyServiceStatus> response = await restResponse;
=>
IRestResponse<DummyServiceStatus> response = await restResponse.ConfigureAwait(false);
I've described this pitfall in my blog post Pitfalls of async/await
You are blocking the UI by using Task.Result property.
In MSDN Documentation they have clearly mentioned that,
"The Result property is a blocking property. If you try to access it
before its task is finished, the thread that's currently active is
blocked until the task completes and the value is available. In most
cases, you should access the value by using Await or await instead of
accessing the property directly."
The best solution for this scenario would be to remove both await & async from methods & use only Task where you're returning result. It won't mess your execution sequence.
An addition to the answer given by #HermanSchoenfeld. Unfortunately the quote below is not true:
No deadlock issues will occur due to the use of Task.Run.
public String GetSqlConnString(RubrikkUser user, RubrikkDb db)
{
// deadlock if called from threadpool,
// works fine on UI thread, works fine from console main
return Task.Run(() =>
GetSqlConnStringAsync(user, db)).Result;
}
The execution is wrapped inside a Task.Run, this will schedule the task on the threadpool the block the calling thread. This is okay, as long as the calling thread is not a threadpool thread. If the calling thread is from the threadpool then the following disaster happens: A new task is queued to the end of the queue, and the threadpool thread which would eventually execute the Task is blocked until the Task is executed.
In library code there is no easy solution as you cannot assume under what context your code is called. The best solution is to only call async code from async code, blocking sync APIs from sync methods, don’t mix them.
Source:
https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d
If you don't get any callbacks or the control hangs up, after calling the service/API async function, you have to configure Context to return a result on the same called context.
Use TestAsync().ConfigureAwait(continueOnCapturedContext: false);
You will be facing this issue only in web applications, but not in static void main.
Error in line: await instance.CreateFile(); The await operator can only be used within an async method. Consider marking this method with the async modifier and changing its return type to Task
It's my understanding that the method is already asynchronous, I'm not sure what I am doing wrong. This is on a UWP app in VS 2015.
public sealed partial class MainPage : Page
{
private List<Customer> Customers;
public MainPage()
{
this.InitializeComponent();
CustomerDataAccessLayer instance = new CustomerDataAccessLayer();
await instance.CreateFile();
}
}
public class CustomerDataAccessLayer
{
public StorageFile mfile;
public async Task CreateFile()
{
mfile = await ApplicationData.Current.LocalFolder.GetFileAsync("Customers.xml");
if (mfile == null)
{
mfile = await ApplicationData.Current.LocalFolder.CreateFileAsync("Customers.xml", CreationCollisionOption.ReplaceExisting);
}
else
{
}
return;
}
}
As others have noted, the error message is complaining that the calling method is not async, but constructors cannot be marked async.
The core problem is that your UI cannot load asynchronously - it must load immediately. I recommend initially loading some kind of "Loading..." state and also starting an asynchronous operation. Then, when that operation completes, update the UI to display the data.
To start an asynchronous action from a synchronous function (like a constructor), you can use a Task.
Task.Run(async () =>
{
//put your async code here
});
To await this Task, you have to use some more code.
Task t = new Task(() => { /*Your code*/ });
t.Wait();
I have a class with an async method:
public static async Task GetData() { ... }
In the app framework I am using I need to start that process and forget about it when the app starts:
protected override void OnStart()
{
await MyService.GetData();
}
I can't make OnStart async. How do I start it in a background task and forget about it?
I can't make OnStart Async. How do I start it in a background task and
forget about it?
Why not? Nothing prevents you from making it async. The async modifier doesn't affect the CLR method signature, i.e., you can override a void method and make it async:
abstract class AppBase
{
protected abstract void OnStart();
}
class App: AppBase
{
public static async Task GetData() { await Task.Delay(1); }
protected override async void OnStart()
{
await GetData();
}
}
This way, at least you'll see an exception if GetData throws, unlike what the other answer suggests.
Make sure you understand how async void methods and Task error handling work in general, this material may be helpful.
Some other problems with Task.Run( () => MyService.GetData() ):
as GetData is already asynchronous, there's very little sense in wrapping it with Task.Run. It's usually only done in a client-side UI app and only if GetData has a long-running synchronous part (before it hits its 1st await). Otherwise, you might as well just call GetData() without Task.Run and without await (which also would be a bad idea: in either case, you'd be doing a fire-and-forget call without observing possible exceptions).
Task.Run will start GetData on a random pool thread without synchronization content, which may be a problem for either a UI app or an ASP.NET app.
If you want to fire this async operation and forget about it all you need to do is invoke the method without awaiting the returned task:
protected override void OnStart()
{
MyService.GetDataAsync();
}
However, since you're not observing the task you would never know if it completed successfully.
You should either keep a reference to the task and await it in a later time:
public Task _dataTask;
protected override void OnStart()
{
_dataTask = MyService.GetDataAsync();
}
public Task AwaitInitializationAsync()
{
return _dataTask;
}
Or add a continuation handling any exceptions:
protected override void OnStart()
{
MyService.GetDataAsync().ContinueWith(t =>
{
try
{
t.Wait();
}
catch (Exception e)
{
// handle exceptions
}
});
}
You shouldn't use Task.Run as Noseratio explained, however using async void is much worse since an exception in an async void method (which isn't a UI event handler) would tear down the entire process*.
You can try to make the method async void while making sure there won't be any exceptions thrown inside it with a try-catch block:
protected override async void OnStart()
{
try
{
await GetData();
}
catch (Exception e)
{
// handle e.
}
}
But I would still recommend against it since even the chance of a complete crash is dangerous.
*You can get around that by registering an even handler for AppDomain.CurrentDomain.UnhandledException but this should be a last resort, not a best practice
I am using MvvmLight and have implemented communication between some of my ViewModels using the MessengerInstance.Send(...) method. It works great!
Recently, though, I have moved from using Synchronous methods to async methods to retrieve data and it looks like this breaks messaging (probably because it executes on a different thread). For example:
public ICommand SomeCommand { get { return new RelayCommand(DoSomething); } }
private async void DoSomething(object obj)
{
//Used to be SomeWcfService.DoSomething(); with some logic afterward
await SomeWcfService.DoSomethingAsync().ContinueWith(task => { //Some logic after method completes });
MessengerInstance.Send(SomeDataToSend, MessageIdentifer.DoSomething);
}
Instead of using a continuation, just put it after the await:
private async void DoSomething(object obj)
{
//Used to be SomeWcfService.DoSomething(); with some logic afterward
var result = await SomeWcfService.DoSomethingAsync();
// .ContinueWith(task => { //Some logic after method completes });
// use result here!
MessengerInstance.Send(SomeDataToSend, MessageIdentifer.DoSomething);
}
If there is no result returned from DoSomethingAsync, you can just leave out the result, and put your code in place.
The continuation, as you wrote it, will not run on the same synchronization context. The await keyword is actually asynchronously waiting your continuation, not the async method from WCF, as well.
If your "some logic" is asynchronous, you can use await within that code, as well.