Call async method with await in it from synchronous action method - c#

I need to implement a service which fire a start of the processing. But I don't need to wait for result. I can just show the default output and in the background the process will be working.
However I came up to the problem that the code after await is not executed.
I prepared some code to show the idea:
public class HomeController : Controller
{
public ActionResult Deadlock()
{
AsyncCall();
return View();
}
private async Task AsyncCall()
{
await Task.Delay(10000);
var nonreachablePlace = "The breakpoint will not set the execution here";
Do(nonreachablePlace);
}
private void Do(string m)
{
m.Contains("x");
}
}
I know that it looks very bad. But the idea was like:
A thread go to Deadlock method.
The thread go to AsyncCall method synchronously.
Faces the await statement.
Go from the Deadlock method.
Continue main method to the end.
When Task.Delay finished, this thread will come up from the thread pool and continue working.
To my bad 6 step is not processed. I have tried to set up the breakpoint and never got hit.
But if I reduce the time delay and do it in debug I will come to the 6 step.
Enter to the controller's action method
After return from controller's action method
But if I leave only one breakpoint after await, I won't go to the 6 step
var nonreachablePlace = "The breakpoint will not set the execution here";
NOTE:
I append ConfigureAwait(false) to the Task.Delay(). It looks like this:
private async Task AsyncCall()
{
await Task.Delay(10000).ConfigureAwait(false);
var nonreachablePlace = "The breakpoint will not set the execution here";
Do(nonreachablePlace);
}
And now it works as expected.
My question is why does the code not work without ConfigureAwait(false)?
Maybe it somehow related to SynchronizationContext and it is not reachable after the main thread finishes its work. And after that awaitable method tryes to get a context when it has been already disposed (Just my thought)

Use HostingEnvironment.QueueBackgroundWorkItem.
Note this is only available in Classic ASP.NET on .NET Framework (System.Web.dll) and not ASP.NET Core (I forget to what extent it works in ASP.NET Core 1.x and 2.x running on .NET Framework, but anyway).
All you need is this:
using System.Web.Hosting;
public class MyController : Controller
{
[HttpPost( "/foo" )]
public async Task<ActionResult> DoSomething()
{
HostingEnvironment.QueueBackgroundWorkItem( this.DoSomethingExpensiveAsync ); // Pass the method by name or as a `Func<CancellationToken,Task>` delegate.
return this.View();
}
private async Task DoSomethingExpensiveAsync( CancellationToken cancellationToken )
{
await Task.Delay( TimeSpan.FromSeconds( 30 ) );
}
}
You can also use it with non-async workloads:
[HttpPost( "/foo" )]
public async Task<ActionResult> DoSomething()
{
HostingEnvironment.QueueBackgroundWorkItem( this.DoSomethingExpensive ); // Pass the method by name or as a `Action<CancellationToken>` delegate.
return this.View();
}
private void DoSomethingExpensive( CancellationToken cancellationToken )
{
Thread.Sleep( 30 * 1000 ); // NEVER EVER EVER call Thread.Sleep in ASP.NET!!! This is just an example!
}
If you want to start a job normally at first and only finish it in the background if it takes too long, then do this:
[HttpPost( "/foo" )]
public async Task<ActionResult> DoSomething()
{
Task<String> workTask = this.DoSomethingExpensiveAsync( default );
Task timeoutTask = Task.Delay( TimeSpan.FromSeconds( 5 ) );
Task first = await Task.WhenAny( workTask, timeoutTask );
if( first == timeoutTask )
{
// `workTask` is still running, so resume it in the background:
HostingEnvironment.QueueBackgroundWorkItem( async ct => await workTask );
return this.View( "Still working..." );
}
else
{
// `workTask` finished before the timeout:
String result = await workTask; // or just `workTask.Result`.
return this.View( result );
}
}
private async Task<String> DoSomethingExpensiveAsync( CancellationToken cancellationToken )
{
await Task.Delay( TimeSpan.FromSeconds( 30 ) );
return "Explosive bolts, ten thousand volts; At a million miles an hour, Abrasive wheels and molten metals";
}

So Deadlock() calls AsyncCall()
Then AsyncCall() Tells DeadLock() "Okay, well I'm waiting for Task.Delay to count to 10,000 but you can go ahead."
...so AsyncCall() yields the main thread back over to DeadLock().
Now DeadLock() never said anything about waiting on AsyncCall() to finish, so as far as DeadLock() is concerned, AsyncCall() has already returned (it actually only yielded, but the program cursor would still be passed back out into DeadLock().
So I would suggest setting your breakpoint at the AsyncCall() method in DeadLock(), because you'll probably see that your main thread is already done and exited before the Task.Delay() is even done.
So AsyncCall() never even gets a chance to finish Awaiting.

I dived deep into the logic behind Task.Delay(10000) and continuation code after that.
Thanks to the post made by Stephen Toub.
The main problem was in part when a Task had finished. And it's result needed to be processed by next thread.
Since I hadn't written ConfigureAwait() I implicitly meant to run the code in a thread which has SynchronizationContext (AspNetSynchronizationContext in my case).
private async Task AsyncCall()
{
/// The delay is done by a thread from a ThreadPool.
await Task.Delay(10000);
/// After the Task has been finished
/// TaskAwaiter tryies to send a continuation code to a thread with
/// SynchronizationContext.
var nonreachablePlace = "The breakpoint will not set the execution here";
Do(nonreachablePlace);
}
Because I hadn't wanted to wait the result of awaitable, I returned the response from controller's action. Then the thread went to ThreadPool and SynchronizationContext was disposed.
To the moment of Task completion, there was no SynchronizationContext to send a delegate with continuation code.
And during the code creation Visual Studio Enabled Just My Code option was set to true. That's why this exception was thrown silently to me.
And about the situation when I was able to run a code even I had Task.Delay(2000). I think it's caused by the time needed to Classic ASP.NET to complete a request and create a response to it. During this time you can get a reference to SynchronizationContext and Post a delegate to it.

Related

Async method blocking on unawaited task

In my current project, I have a piece of code that, after simplifying it down to where I'm having issues, looks something like this:
private async Task RunAsync(CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask();
}
private Task<bool> FakeTask()
{
return Task.FromResult(false);
}
If I use this code without awaiting, I end up blocking anyway:
// example 1
var task = RunAsync(cancel); // Code blocks here...
... // Other code that could run while RunAsync is doing its thing, but is forced to wait
await task;
// example 2
var task = RunAsync(cancelSource.Token); // Code blocks here...
cancelSource.Cancel(); // Never called
In the actual project, I'm not actually using FakeTask, and there usually will be some Task.Delay I'm awaiting in there, so the code most of the time doesn't actually block, or only for a limited amount of iterations.
In unit testing, however, I'm using a mock object that does pretty much do what FakeTask does, so when I want to see if RunAsync responds to its CancellationToken getting cancelled the way I expect it to, I'm stuck.
I have found I can fix this issue by adding for example await Task.Delay(1) at the top of RunAsync, to force it to truly run asynchronous, but this feels a bit hacky. Are there better alternatives?
You have an incorrect mental picture of what await does. The meaning of await is:
Check to see if the awaitable object is complete. If it is, fetch its result and continue executing the coroutine.
If it is not complete, sign up the remainder of the current method as the continuation of the awaitable and suspend the coroutine by returning control to the caller. (Note that this makes it a semicoroutine.)
In your program, the "fake" awaitable is always complete, so there is never a suspension of the coroutine.
Are there better alternatives?
If your control flow logic requires you to suspend the coroutine then use Task.Yield.
Task.FromResult actually runs synchronously, as would await Task.Delay(0). If you want to actually simulate asynchronous code, call Task.Yield(). That creates an awaitable task that asynchronously yields back to the current context when awaited.
As #SLaks said, your code will run synchronously. One thing is running async code, and another thing is running parallel code.
If you need to run your code in parallel you can use Task.Run.
class Program
{
static async Task Main(string[] args)
{
var tcs = new CancellationTokenSource();
var task = Task.Run(() => RunAsync("1", tcs.Token));
var task2 = Task.Run(() => RunAsync("2", tcs.Token));
await Task.Delay(1000);
tcs.Cancel();
Console.ReadLine();
}
private static async Task RunAsync(string source, CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask(source);
}
private static Task<bool> FakeTask(string source)
{
Console.WriteLine(source);
return Task.FromResult(false);
}
}
C#'s async methods execute synchronously up to the point where they have to wait for a result.
In your example there is no such point where the method has to wait for a result, so the loop keeps running forever and thereby blocking the caller.
Inserting an await Task.Yield() to simulate some real async work should help.

Breakpoint not hitting after .Wait()

i have a .net web api 2 method where i am trying to have some part of my code do something in a separate thread, however after I call the .Wait() method on the task it never hits the next line. I must be overlooking something, but I can't seem to find it. Here's a very simple version of the issue. The line Ok() never gets hit. Any suggestions?
public IHttpActionResult Get() {
var attachTask = AttachNewTasksAsync();
//do something else
attachTask.Wait();
return Ok();
}
public async System.Threading.Tasks.Task AttachNewTasksAsync()
{
await System.Threading.Tasks.Task.Delay(10000);
}
Deadlock. Your main thread is waiting for attachTask to finish and attachTask cannot finish, because it is waiting for main thread.
Either add ConfigureAwait(false) to Task.Delay or do it properly and await attachTask
This is how it should be written:
public async Task<IHttpActionResult> Get() {
var attachTask = AttachNewTasksAsync();
//do something else
await attachTask;
return Ok();
}
How to ensure that deadlock will not happen even if someone waits for it synchronously? Use ConfigureAwait(false).
public async System.Threading.Tasks.Task AttachNewTasksAsync()
{
await System.Threading.Tasks.Task.Delay(10000).ConfigureAwait(false);
}
There is probably nothing I can write, that isn't already covered by Stephen Cleary's blog, so I will just leave this link here.

Wait() method of a task bloks the Task

I am working in Xamarin where I have a Task that I start at the first menupage, go through several other menupages, and then want to wait for it's completion when opening an endpage. To do this I save the task in a static field when starting it:
private static Task myTask;
public static void sync(User user)
{
if (myTask== null || myTask.IsCompleted) {
myTaskStarted = true;
//Note: do not trust on the variable being filled in immediately after the start of the task. It takes a minute. Use the flag
myTask= AsyncMyTask(user);
}
}
And then later I call a method from another page that is simply supposed to wait for myTask to finnish by calling myTask.Wait() after doing some checks on myTask having been started and not being null. But I see that once I call myTask.Wait() myTask is stuck and no longer progresses in the debugger. It's stuck. If I replace myTask.Wait() by myTask.Wait(1000) myTask is frozen for the duration of the timeout. After the timeout it continues. This is not the behaviour that is described in the documentation. Can anyone explain why the AsyncMyTask method is blocked when you call myTask.Wait() from the UI thread?
As requested: the AwaitMyTask method:
public async static Task<Boolean> AwaitMyTask()
{
if(!myTaskStarted && myTask== null)
{
return false;
} else
{
while (myTask== null)
{
Task.Delay(10);
}
}
//Stuck on the line below
myTask.Wait();
myTaskStarted = false;
return myTask.IsCompleted;
}
Task.Wait is a synchronously awaiting the task which blocks the thread. Unless you can point to a documentation stating something else, I'd say that it's expected behavior as described in https://msdn.microsoft.com/en-us/library/dd235635(v=vs.110).aspx
Wait is a synchronization method that causes the calling thread to wait until the current task has completed. ...

Does a method has to be async when invoked inside an async method?

Lets say I have a method defined as follows:
public async Task CreateUser()
{
await GetUserDetails();
GetUserOrder();
}
private void GetUserDetails() {
private void GetUserOrder() {
Does the method GetUserDetails(); and GetUserOrder() have to be async as well to avoid UI blocking ?
I cannot await the GetUserDetails() method since it is not async. How can I achieve this in c# ? I want to ensure all these methods are invoked step by step.
The relevant question is in a comment:
How can I ensure all my methods are invoked completely sequentially?
The fact that you're asking the question indicates that you don't understand what "await" is. Await is the sequencing operation on a asynchronous workflows. An await means this workflow will not proceed until the awaited task is complete. It's an asynchronous wait, hence the name await.
Consider this question: in a synchronous workflow, what is the sequencing operation?
No, really, give it some thought.
.
.
.
It is ;. When you say
fResult = foo();
bResult = bar();
qResult = qux();
that means that foo has to finish completely before bar can begin. That is not true for asynchronous workflows. If we have
fTask = fooAsync();
bTask = barAsync();
qTask = quxAsync();
Then the asynchronous operations can complete in any order. If we say
await fooAsync();
await barAsync();
await quxAsync();
Then barAsync will not start until fooAsync's task completes. await sequences the asynchronous workflow. The difference is that the thread can continue to do other unrelated work while asynchronously waiting for foo to complete, which is not true in a synchronous workflow; in a synchronous workflow the thread is already busy computing the foo result, so it can't do other work.
yes if you want to wait than you have to write await for that methods also. because after first await your code agian will be synchronous ..and if UI thread than it will run on it.
1.you code will be , so by this code you code become asynchronous for GetUserORder also. you just have to wrap method in Task construct and return
public async Task CreateUser()
{
await GetUserDetails();
await Task.Factory.SartNew(()=> GetUserOrder());
}
2.or you can do this also
public async Task CreateUser()
{
await Task.Factory.SartNew(()=>{
GetUserDetails();
GetUserOrder(); });
}
3.or you can do like this also, in below code will not wait for getuserorder method and excute await one method
public async Task CreateUser()
{
Task.Factory.SartNew(()=> GetUserOrder()).ContinueWith((t)=> Console.WriteLine("Completed");
await GetUserDetails();
}
4.or last one variation, here you start GetUserOrder first and dont wait for it than you call GetUserDetails in async fashion , and if you want to work on GetUserOrder method want to wait just use Wait method.
public async Task CreateUser()
{
var task = Task.Factory.SartNew(()=> GetUserOrder());
await GetUserDetails();
if(!task.IsCompleted)
task.Wait();
}
in your case you can go for 3 and if you want to wait go for 4th one.
As you asked me in comment what is difference between Task.Run and statnew method -: for that you can check this SO question : Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()
You should put await only in front of async methods. To run a synchronous one that you don't want to wait, you can use a new thread from the tread pool:
new Thread(() => DoSomething()).Start();
or
Task.Factory.SartNew(()=> DoSomething());
Here is the help page: https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
Otherwise, your call to GetUserDetails will have to finish before you execute the next line.

Asyc method using await Task.Run() never "completes"

I have a method that is defined as
public async Task SomeAsyncMethod()
{
DoSomeStuff();
await Task.Run(() => {
DoSomeSyncStuff();
DoSomeOtherSyncStuff();
});
var someDebugVariable = "someDebugValue";
}
The method itself does exactly what it is supposed to do and everything runs fine. Yet ... it looks like the "outer" async Task never completes.
Example: When I call it like this
public void CallerMethod()
{
Task t = SomeAsyncMethod();
t.Wait();
}
the t.Wait() never completes. Furthermore: if I place a breakpoint at the assignment of someDebugVariable it never gets hit.
I might add that DoSomeSyncStuff and DoSomeOtherSyncStuff really do what they are supposed to and debugging through them tells me that they both complete.
To prove my point I modified my method like this, and the results are still the same.
public async Task SomeAsyncMethod()
{
DoSomeStuff();
await Task.Run(() => {
/*
DoSomeSyncStuff();
DoSomeOtherSyncStuff();
*/
var a = 2; var b = 3; var c = a + b;
});
var someDebugVariable = "someDebugValue";
}
EDIT
I have tried removing everything but the await Task.Run and it does not change anything. It still does not complete.
The application is a WPF application. The caller thread is the UI thread.
What am I missing here?
The t.Wait() call is causing a deadlock, and also makes the async call entirely pointless. I believe if you change the code to
await Task.Run(() => {
// ...
}).ConfigureAwait(false);
You can fix the deadlock and let the code proceed, but you should really get rid of the t.Wait() call. Anything that needs to be done with the results of the sync function calls should be done after the awaited task, not after the call of the async function.
More in depth:
task.Wait() will block all execution on the main thread while the task is running. When the await task completes, it tries to marshall back to the main thread, but the main thread is blocked! Since A is waiting for B, and B is waiting for A, you get a deadlock.
See: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Categories

Resources