We say that, if an awaited expression is not complete then an async method
pauses and returns to the caller.
Once the awaited expression is complete, it resumes it execution.
On which context it resumes is dictated by ConfigureAwait.
But what happens in between pausing and returning to the caller and resuming after the awaited expression is completed.
Where does the awaited expression execute mean while ?
On a Thread Pool thread or UI's thread.
private async void Button_Click(object sender, RoutedEventArgs e)
{
// will resume on UI's context.
button.Content = await GetString().ConfigureAwait(true);
}
private async Task<string> GetString()
{
// where does this section of code runs ?
return await Task.Delay(3000).ContinueWith(x => "Async Content");
}
Neither thread pool nor UI thread. It does not execute at all. When Task.Delay is called, the Delay method creates a Timer and both GetString and Button_Click return.
After 3000 milliseconds the Timer callback gets executed on some thread pool thread. It completes the task and schedules task continuations, and the rest of code in GetString and Button_Click is executed on respective threads.
Related
I am using akka.NET. In most cases we use akka like this:
class ActorA : UntypedActor
{
public delegate void EventHandler(object arg1, object arg2, ...);
public static event EventHandler Event;
}
actorA.Event += some_function;
In this case we execute some_function(arg1, arg2) whenever Event.Invoke(arg1, arg2) is called. Now assume that we have an asynchrounous HTTP server, and I am trying to let the server asynchronously await actorA.Event to happen, after a client calls the server. I do not need to run some_function when Event happens, but I have to ensure that the runtime context is switched back into the functions of the HTTP server. That is:
// in the methods of the HTTP server...
public async void AwaitAnEvent()
{
await ReturnOnEvent(actorA.Event);
}
Is it possible to efficiently implement ReturnOnEvent which returns immediately when the next actorA.Event.Invoke(arg1, arg2) is called?
This case smells a bit.
inside the web controller just ask your actor and that will trigger it to generate response.
When asking it will await in the controller to get response.
var response = myActor.Ask<ResponseType>(new GiveMySomeFoodMsg());
-- in the actor
Sender.Tell(new ResponseType(some data here))
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
How do I run an async task in a Kestrel process with a very long time interval (say daily or perhaps even longer)? The task needs to run in the memory space of the web server process to update some global variables that slowly go out of date.
Bad answers:
Trying to use an OS scheduler is a poor plan.
Calling await from a controller is not acceptable. The task is slow.
The delay is too long for Task.Delay() (about 16 hours or so and Task.Delay will throw).
HangFire, etc. make no sense here. It's an in-memory job that doesn't care about anything in the database. Also, we can't call the database without a user context (from a logged-in user hitting some controller) anyway.
System.Threading.Timer. It's reentrant.
Bonus:
The task is idempotent. Old runs are completely irrelevant.
It doesn't matter if a particular page render misses the change; the next one will get it soon enough.
As this is a Kestrel server we're not really worried about stopping the background task. It'll stop when the server process goes down anyway.
The task should run once immediately on startup. This should make coordination easier.
Some people are missing this. The method is async. If it wasn't async the problem wouldn't be difficult.
I am going to add an answer to this, because this is the only logical way to accomplish such a thing in ASP.NET Core: an IHostedService implementation.
This is a non-reentrant timer background service that implements IHostedService.
public sealed class MyTimedBackgroundService : IHostedService
{
private const int TimerInterval = 5000; // change this to 24*60*60 to fire off every 24 hours
private Timer _t;
public async Task StartAsync(CancellationToken cancellationToken)
{
// Requirement: "fire" timer method immediatly.
await OnTimerFiredAsync();
// set up a timer to be non-reentrant, fire in 5 seconds
_t = new Timer(async _ => await OnTimerFiredAsync(),
null, TimerInterval, Timeout.Infinite);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_t?.Dispose();
return Task.CompletedTask;
}
private async Task OnTimerFiredAsync()
{
try
{
// do your work here
Debug.WriteLine($"{TimerInterval / 1000} second tick. Simulating heavy I/O bound work");
await Task.Delay(2000);
}
finally
{
// set timer to fire off again
_t?.Change(TimerInterval, Timeout.Infinite);
}
}
}
So, I know we discussed this in comments, but System.Threading.Timer callback method is considered a Event Handler. It is perfectly acceptable to use async void in this case since an exception escaping the method will be raised on a thread pool thread, just the same as if the method was synchronous. You probably should throw a catch in there anyway to log any exceptions.
You brought up timers not being safe at some interval boundary. I looked high and low for that information and could not find it. I have used timers on 24 hour intervals, 2 day intervals, 2 week intervals... I have never had them fail. I have a lot of them running in ASP.NET Core in production servers for years, too. We would have seen it happen by now.
OK, so you still don't trust System.Threading.Timer...
Let's say that, no... There is just no fricken way you are going to use a timer. OK, that's fine... Let's go another route. Let's move from IHostedService to BackgroundService (which is an implementation of IHostedService) and simply count down.
This will alleviate any fears of the timer boundary, and you don't have to worry about async void event handlers. This is also a non-reentrant for free.
public sealed class MyTimedBackgroundService : BackgroundService
{
private const long TimerIntervalSeconds = 5; // change this to 24*60 to fire off every 24 hours
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Requirement: "fire" timer method immediatly.
await OnTimerFiredAsync(stoppingToken);
var countdown = TimerIntervalSeconds;
while (!stoppingToken.IsCancellationRequested)
{
if (countdown-- <= 0)
{
try
{
await OnTimerFiredAsync(stoppingToken);
}
catch(Exception ex)
{
// TODO: log exception
}
finally
{
countdown = TimerIntervalSeconds;
}
}
await Task.Delay(1000, stoppingToken);
}
}
private async Task OnTimerFiredAsync(CancellationToken stoppingToken)
{
// do your work here
Debug.WriteLine($"{TimerIntervalSeconds} second tick. Simulating heavy I/O bound work");
await Task.Delay(2000);
}
}
A bonus side-effect is you can use long as your interval, allowing you more than 25 days for the event to fire as opposed to Timer which is capped at 25 days.
You would inject either of these as so:
services.AddHostedService<MyTimedBackgroundService>();
I have a task created as follows.
var task = Task.Factory.FromAsync<Request, Response>(
service.BeginOp,
service.EndOp,
request,
null);
When I await the task in a try/catch, the exception is not caught.
try
{
await task;
}
catch (Exception e)
{
// Block never reached
}
However when I use ContinueWith(), the exception is caught.
await task.ContinueWith(t =>
{
if (t.Exception != null)
{
// Block reached
}
});
Why is it not caught in the first case? I have try/caught other Tasks and it catches the exception.
I suspect that further up your call stack, your code is calling Task<T>.Result or Task.Wait. This will cause a deadlock, as I explain on my blog.
By default, await will capture a "context" whenever it awaits a Task. In this case, the "context" is the ASP.NET request context, which only allows one thread in at a time. If your code blocks a thread within that request context (e.g., by calling Result/Wait), then when the task completes, it cannot resume executing the async method because the context only allows one thread in.
Turns out that in the above callstack I was not using await. I am not sure why the compiler allowed this. Adding the await fixed the problem.
In my Singleton-EJB i start a TimerService every 2 minutes. When a client access the test method
sometimes the application runs into a deadlock. The problem is, the test method calls a asynchronous method inside the EJB (see Method determineABC). The deadlock happens when the scheduleMethod tries to create a single action timer and therefore tries to acquire a lock (because hte timer callback method is annotated with LOCK.WRITE). At the same time we are already in the determineABC Method which tries to invoke the asynchronous method asynchMethod. Maybe the call of ejbLocal.asynchMethod(...); also tries to acquire a lock. Anyway here i run into a deadlock, because the asynchronous method is never called. So what is the problem?
Here is a source code snippet:
#Singleton
#Startup
#TransactionManagement(TransactionManagementType.CONTAINER)
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class XEJB implements XEJBLocal {
#javax.annotation.Resource(name = "x/XEJB/TimeService")
private TimerService timerService;
#javax.annotation.Resource
private SessionContext ctx;
#Schedule(minute = "*/2", hour = "*", persistent = false)
#Lock(LockType.READ)
private void scheduleMethod() {
// Create Single Action Timer
timerService.createSingleActionTimer(new Date(), new TimerConfig(null, false));
}
#Timeout
#Lock(LockType.WRITE)
private void timer(Timer timer) {
// Do something
}
#Override
#Lock(LockType.READ)
public B test(...) {
return determineABC(...);
}
#Lock(LockType.READ)
private B determineABC(...) {
XEJBLocal ejb= (XEJBLocal) ctx.getBusinessObject(ctx.getInvokedBusinessInterface());
Future<ArrayList> result = null;
result = ejb.asynchMethod(...);
result.get(4, TimeUnit.MINUTES); // Sometimes runs into a DEADLOCK
...
}
#Asynchronous
#Override
#Lock(LockType.READ)
public Future<ArrayList> asynchMethod(...) {
...
return new AsyncResult<ArrayList>(abcList);
}
The Deadlock also happens when i only use the #Schedule Method and no TimerService...
The DeadLock also happens when i do not use a Future Object but void as return type of the asynchronous Method.
When the timeout Exception is thrown the deadlock is solved. When i annotate the timer method with #AccessTimeout(2000) and this time is up the asynchronous method is called and therefore the deadlock is also solved.
When i use Locktype.READ for the timer Method no Deadlock happens. But why? What does the asychronous method call?
READ locks have to wait for WRITE locks to finish before they start their work. When timer() is working all your other invokations, even to READ methods, are going to wait. Are you sure the timeout happens in result.get(4, TimeUnit.MINUTES);?
I think you may be have access timeouts in test() invokation, way before reaching result.get(4, TimeUnit.MINUTES);.