How does a Task get to know when it has completed? - c#

The Task does not maintain a wait handle for performance reasons, and only lazily constructs one if the code were to ask one of it.
How then does a Task know it has been completed?
One would argue that the implementer sets the result on the TaskCompletionSource in their implementation but that would explain only the modern implementations and re-writes such as System.IO.FileStream.Begin/EndReadTask.
I followed the Task.IsComplete property; almost in every instance, an internal bitwise flag field (m_stateFlags) is set by the TrySetResult / TrySetException methods to indicate the status of the task.
But that does not cover all cases.
What about a method such as this?
public async Task FooAsync()
{
await Task.Run(() => { });
}

How then does a Task know it has been completed?
As I describe on my blog (overview, more detail), there are two kinds of tasks: Delegate Tasks (which execute code) and Promise Tasks (which represent an event).
Delegate Tasks complete themselves when their delegate completes.
Promise Tasks are completed from an external signal, using TaskCompletionSource<T> (or equivalent methods that are internal to the BCL).

I am answering my own question because I have suddenly remembered that I know the answer to it.
When using the C# Language Support Features
It's the state machine.
If the implementer of the asynchronous method used the C# language support such as the async keyword in the method declaration and the await keyword inside the method body to await an operation intrinsic to the task, then to the extent of the task he is implementing, the state machine signals task completion by setting the result of the task.
For e.g. if his implementation was as such:
// client code
public async void TopLevelMethod()
{
await MyMethodAsync();
}
// library code -- his implementation
public async Task MyMethodAsync()
{
await AnotherOperationAsync();
}
Then the completion of MyMethodAsync will be entrusted to the compiler generated state machine.
Of course, the signaling of completion of AnotherOperationAsync will also be taken care of by the compiler generated state machine, but that is not the point here.
Recall the states inside the MoveNext method indicate the task completion states and in the block inside of MoveNext that invokes the continuation callback, it also calls SetResult on the AsyncXXXMethodBuilder.
When not using the C# Language Support Features
If, however, the implementer of the asynchronous method did not make use of the C# language features, then it is the duty of the implementer to signal the completion of the task by setting the relevant result, exception or cancelled properties on the TaskCompletionSource object.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource<object>();
try
{
AnotherOperation();
tcs.SetResult();
}
catch(Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
If the implementer did not use TPL support or invoked another operation asynchronously using the older .NET API, then too, it is the implementer's responsibility to signal task completion by explicitly setting the status of the task through one of the Try/SetResult/Exception etc. methods.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource...
var autoReseEvent = ...
ThreadPool.QueueUserWorkItem(new WaitCallback(() =>
{
/* Work */
Thread.SpinWait(1000);
tcs.SetResult(...);
autoResetEvent.Set();
};)...;
return tcs.Task;
}
An Ill-Advised Case
The best way to await a task is, of course, to use the await keyword. If, however, when implementing an asynchronous API, the implementer does this:
public Task MyMethodAsync()
{
return Task.Run(...);
}
That would leave the consumer of his API with a sour mouth, I suppose?
Task.Run should only ever be used in a fire and forget scenario where you do not care about the point in time when the task will be completed.
The one exception to this is if you awaited the task returned by the call to Task.Run using the await keyword, like the code snippet shown below, in which case, you would be using the language support as described in the first section.
public async Task MyMethodAsync()
{
await Task.Run(...);
}

Related

What exactly in an awaitable is being awaited? How do I make a Task properly?

I've searched a lot of information surrounding this topic and I understand the general premises of:
Await is a handing off of control from the callee backer to the caller
Most Modern I/O doesn't use real threading in underlying architecture
Most async methods do not explicitly spin up their own threads (i.e. Web Requests)
The last bullet in particular is what I want to discuss. To future-proof this let's use an example as a medium for explanation. Let's assume this is the code block:
public async Task<int> LongOperationWithAnInt32ResultAsync(string input)
{
/// Section A
_ = int.TryParse(input, out var parsedInt)
parsedInt = SyncOperationWithAnInt32Result(parsedInt);
/// Section B
await MyCustomTaskThatIWantAwaited();
/// Section C
return parsedInt;
}
private Task MyCustomTaskThatIWantAwaited()
{
/// Section D
AnotherSyncOperationWithVoidResult();
/// Section E
return Task.CompletedTask;
}
The method LongOperationWithAnInt32ResultAsync(string) will perform synchronously even though this is not the intended effect.
This is because when the caller enters the callee at Section B, the
code from Section D and Section E are executed immediately and are not
awaited. This behavior is changed if, Section D is removed and,
Section E was "return Task.Run(() =>
AnotherSyncOperationWithVoidResult())" instead. In this new Section E,
the awaitable being tracked becomes the thread from Task.Run (wrapped
with the returned Task).
If you replace Section B with "await Task.Delay(10000);" or "await FunctionalWebRequestAsync();" it works as intended. However, to my knowledge, neither of these internally generate a thread to be followed - so what exactly is being awaited?
I've accepted the main answer because it really helped me understand my misconception on Task functionality, but please also refer to my answer as well. It may be what you're looking for.
so what exactly is being awaited?
Nothing is being awaited. Await means asynchronous wait. For a wait to be asynchronous, the awaitable (the Task) should not be completed at the await point. In your case the awaitable is already completed (the IsCompleted property of the TaskAwaiter returns true), so the async state machine grabs immediately its result and proceeds with the next line as usual. There is no reason to pack the current state of the machine, invoke the OnCompleted method of the awaiter, and hand back an incomplete Task to the caller.
If you want to offload specific parts of an asynchronous method to the ThreadPool, the recommended way is to wrap these parts in Task.Run. Example:
public async Task<int> LongOperationWithAnInt32ResultAsync(string input)
{
/// Section A
_ = int.TryParse(input, out var parsedInt)
parsedInt = await Task.Run(() => SyncOperationWithAnInt32Result(parsedInt));
/// Section B
await Task.Run(async () => await MyCustomTaskThatIWantAwaited());
/// Section C
return parsedInt;
}
If you like the idea of controlling imperatively the thread where the code is running, there is a SwitchTo extension method available in the Microsoft.VisualStudio.Threading package. Usage example:
await TaskScheduler.Default.SwitchTo(); // Switch to the ThreadPool
The opinion of the experts is to avoid this approach, and stick with the Task.Run.
Huge thanks to #TheodorZoulias for his explanation and answer as it was critical in me reaching this point.
My misconception was simple, Task (or Task{T}) cannot be used as a delegate. Task is a class through and through, meaning that if you define this:
public Task DoSomeReallyLongWork()
{
SyncTaskThatIsReallyLong();
AnotherSyncTaskThatIsReallyLong();
/* perform as much work as needed here */
return Task.CompletedTask;
}
This will run synchronously and ONLY synchronously. The thing actually being awaited is the Task.CompletedTask object that you returned, nothing else. And since the Task is already completed, the internal awaiter is also marked as completed.
This means that though the intention may have been to wrap multiple methods within a Task and then execute/await it, what's actually happening is that the methods are executing synchronously like any other call and then a completed Task is being returned.
If you want multiple methods to be awaited, this is done by making a new Task Object. Using our previous example:
public async Task DoSomeReallyLongWorkAsync()
{
/// Task.Run does not necessarily run on a separate thread
/// this is up to the scheduler (usually the .NET scheduler)
await Task.Run(LongSyncTasksWrapped);
}
public void LongSyncTasksWrapped()
{
SyncTaskThatIsReallyLong();
AnotherSyncTaskThatIsReallyLong();
/* perform as much work as needed here */
return;
}
There may be instances where you want cold Tasks (task that haven't been started yet) and then run them when needed. Using the previous example, this would be done by:
public async Task DoSomeReallyLongWorkAsync()
{
var coldTask = new Task(LongSyncTasksWrapped);
/// Must call .Start() whenever you want the Task to
/// actually start. Await will not start the Task, its
/// just an asynchronous form of .Wait()
coldTask.Start();
/// coldTask was considered "hot" from .Start()
/// await is waiting a hot task.
await coldTask;
}
public void LongSyncTasksWrapped()
{
SyncTaskThatIsReallyLong();
AnotherSyncTaskThatIsReallyLong();
/* perform as much work as needed here */
return;
}
This answers the question of what's being awaited, its the Task's awaiter that is internally generated by the class.

C# Task.Delay(1).Wait() deadlocks but only if inside another Task [duplicate]

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.

Is awaiting methods from synchronous sources with await Task.Run(() => good practice?

I have a method that has the async keyword with a task. This method returns a string that comes from JwtSecurityTokenHandler().WriteToken(t); The thing is none of the assignments in the body of the method are awaitable.I get the warning CS-1998. That says you shouldnt use async for synchronous methods which makes complete sense. But then it adds that you can use await Task.Run(() => { . So is it good practice to do this?
public async Task<object> GenerateMyUserJwtToken(string email, IdentityUser user)
//code that isnt awaitable
{
var u = await Task.Run(() =>
{
return new JwtSecurityTokenHandler().WriteToken(token);
});
return u;
}
edit: I did not ask what the error was I asked if it was a good idea to Implement await Task.Run(() on an async method signature that has no await assignments. I also asked that another async method is awaiting this in the another method here is the code
//awaiting method:
public async Task<object> LoginAsync(LoginDto model)
{
return await GenerateMyUserJwtToken(model.Email, appUser);
}
//controller:
[HttpPost("login")]
public async Task<object> Login([FromBody] LoginDto model)
{
var logMeIn = await new AuthUserService().LoginAsync(model);
return logMeIn; //returns token
}
My Question is is this async all the way or does the task.Run stop that process?
Using Task.Run just to make something sync is generally a bad practice but it cannot be stated generally.
If the sync method to execute may take for a long time, then it can be a solution. Please note that Task.Run will assign the task to a pool thread and it is not always desirable. It is a common misunderstanding that async methods always use or should use threads somewhere at the end of the async-await chain. However, async-await has nothing to do with threads, it is about asynchronicity (chaining deferred tasks) and creating threads is just one option to create awaitable tasks.
So what are the options?
The method to call is fast and never blocks the caller for long time (>100ms or so): do not use async at all. In this case Task<T>.FromResult(result) is a tempting solution but is highly discouraged because it is misleading for the caller. Use it only in unit tests or if you are forced to implement an async method of an interface you cannot change.
The method execution takes for a long time because it is CPU bound: now you can use a thread. But I typically would not use pool threads for long lasting tasks as it can cause nasty side effects if the thread pool is out of threads. Use await Task.Factory.StartNew(() => MyLongRunningTask(), cancellationToken, TaskCreationOptions.LongRunning); instead, which creates a brand new thread instead of bothering the pool.
The method execution takes for a long time because it is IO bound (eg. sending/receiving packets via a hardware): Use TaskCompletitionSource<T>, add a hook to the whatever completition event of the device (eg. OS hook or IRQ notification) and from that set the result of the completition source and return its task.

Making async method properly

I googled a lot and for the moment the only async implementation I found (including MSDN site) is the following:
public async void Foo()
{
...
await StreamReader.ReadAsync();
...
}
So in all the cases they use some method which is already async. And this is not what I need.
Let's say that I have a heavy method that does something:
public void DoSomthing()
{
...
}
And there is method where I call this DoSomething:
public void MajorMethod()
{
DoSomething();
}
I want to make DoSomething ayncthonous and call it.
The only solution I see would be the following one:
public Task MajorMethod()
{
return Task.Run(()=>DoSomething());
}
But I read some comments that it's not really the async. So how can I make DoSomething async?
If the MajorMethod has no other things to do other than calling the DoSomething, your code is fine.
But if you need to do other stuff after calling to DoSomething, then mark MajorMethod as async, and use await before Task.Run
public async Task MajorMethod()
{
await Task.Run(()=>DoSomething());
//stuff in here will executed after DoSomething completed
}
Examples from MSDN: Asynchronous programming
or just google c# async
You should be clear about the role async/await play in the Task Asynchronous Pattern. Making an async method does not parform an operation asynchronously just like that. Marking an existing method async will not magically perform everything in there asynchronously. Its main effect is that now you are allowed to use await within the method (I read that it even was discussed if the async keyword was necessary at all; it was added to avoid a breaking change when a local variable in existing methods would be named await).
await also does not provide asynchrony by itself, it provides a way to synchronize to another asnychronous method and yield while the other operation is still running. You can await another async method, but unless somwhere down the chain there is an actual Task running in another thread, the async method might even return synchronously.
In consequence this means that you need an operation that runs asynchronously first (such as a DB query, file access, network communication) and from there you create a chain of async methods that await the previous method.
Now in your case, when you have a computationally intensive method that does not wait for external resources, you can choose to perform the operation asynchronously. Since modern CPUs usually have more than one core at your disposal, you can increase both, performance and application responsiveness like that. The method would not be async, since it does not await anything:
void DoSomething()
{
//...
}
Task DoSomethingAsync() {
return Task.Run(DoSomething);
}
All callers of DoSomethingAsync can now use await to synchronize with this operation running in the background (note the change in return type to Task to allow callers to await):
async Task MajorMethod() {
//...
await DoSomethingAsync();
//...
}
This would allow callers of MajorMethod to synchronize with it. What you can also do is to do stuff in MajorMethod while DoSomethingAsync is running (and still await to allow callers to do even more parallel operations):
async Task MajorMethod() {
//This part will run before DoSomethingAsync
//...
Task doSomethingTask = DoSomethingAsync();
//This part is executed at the same time as DoSomethingAsync
//...
await doSomethingTask; //Here the caller can do more operations while DoSomething is running
//This part will be executed after DoSomethingAsync has finished
//...
}
This form of acquiring a task, doing something and only then awaiting the task has to be done somewhere in the chain, otherwise you have no benefit from the asynchronous operation. Even though this might be an overgeneralization, since synchronization can happen in more subtle ways, for example with a custom synchronization context. But as far as your question is concerned, you should go with: There is an actual task on one end and something that is done after the async call, but before the await on the other end.

TaskCompletionSource usage in IO Async methods

The implementation of the ExecuteNonQueryAsync() method in System.Data.SqlClient.SqlCommand is as follows:
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken) {
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteNonQueryAsync|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
SqlConnection.ExecutePermission.Demand();
TaskCompletionSource<int> source = new TaskCompletionSource<int>();
CancellationTokenRegistration registration = new CancellationTokenRegistration();
if (cancellationToken.CanBeCanceled) {
if (cancellationToken.IsCancellationRequested) {
source.SetCanceled();
return source.Task;
}
registration = cancellationToken.Register(CancelIgnoreFailure);
}
Task<int> returnedTask = source.Task;
try {
RegisterForConnectionCloseNotification(ref returnedTask);
Task<int>.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null).ContinueWith((t) => {
registration.Dispose();
if (t.IsFaulted) {
Exception e = t.Exception.InnerException;
source.SetException(e);
}
else {
if (t.IsCanceled) {
source.SetCanceled();
}
else {
source.SetResult(t.Result);
}
}
}, TaskScheduler.Default);
}
catch (Exception e) {
source.SetException(e);
}
return returnedTask;
}
Which I would summarize as:
Create TaskCompletionSource<int> source = new TaskCompletionSource<int>();
Create a new task using Task<int>.Factory.FromAsync, using the APM "Begin/End" API
Invoke source.SetResult() when the task finishes.
Return source.Task
What is the point of using TaskCompletionSource here and why not to return the task created by Task<int>.Factory.FromAsync() directly? This task also has the result and exception (if any) wrapped.
In C# in a Nutshell book, in the Asynchronous Programming and Continuations section, it states:
In writing Delay, we
used TaskCompletionSource, which is a standard way to implement “bottom-level”
I/O-bound asynchronous methods.
For compute-bound methods, we use Task.Run to initiate thread-bound concurrency.
Simply by returning the task to the caller, we create an asynchronous method.
Why is it that the compute-bound methods can be implemented using Task.Run(), but not the I/O bound methods?
Note that for a definitive answer, you would have to ask the author of the code. Barring that, we can only speculate. However, I think it's reasonable to make some inferences with reasonable accuracy…
What is the point of using TaskCompletionSource here and why not to return the task created by Task.Factory.FromAsync() directly?
In this case, it appears to me that the main reason is to allow the implementation to deregister the registered callback CancelIgnoreFailure() before the task is actually completed. This ensures that by the time the client code receives completion notification, the API itself has completely cleaned up from the operation.
A secondary reason might be simply to provide a complete abstraction. I.e. to not allow any of the underlying implementation to "leak" from the method, in the form of a Task object that a caller might inspect or (worse) manipulate in a way that interferes with the correct and reliable operation of the task.
Why is it that the compute-bound methods can be implemented using Task.Run(), but not the I/O bound methods?
You can implement I/O bound operations using Task.Run(), but why would you? Doing so commits a thread to the operation which, for an operation that would not otherwise require a thread, is wasteful.
I/O bound operations generally have support from an I/O completion port and the IOCP thread pool (the threads of which handle completions of an arbitrarily large number of IOCPs) and so it is more efficient to simply use the existing asynchronous I/O API, rather than to use Task.Run() to call a synchronous I/O method.

Categories