I run these two versions and it seems like each is giving me the same output, which is sequential.
ContinueWith_Method1a();
ContinueWith_Method1b();
and
Task.Run(() => ContinueWith_Method1a())
.ContinueWith(task => ContinueWith_Method1b())
.Wait();
I tried with the below but get this error:
Cannot implicitly convert type 'void' to 'System.Threading.Tasks.Task'
Task t = Task.Run(() => ContinueWith_Method1a())
.ContinueWith(task => ContinueWith_Method1b())
.Wait();
static void ContinueWith_Method1a()
{
System.Console.WriteLine("Continue With Method 1a started.");
Thread.Sleep(1000);// Simulate task processing time.
System.Console.WriteLine("Continue With Method 1a completed.");
}
static void ContinueWith_Method1b()
{
System.Console.WriteLine("Continue With Method 1b started.");
Thread.Sleep(1000);// Simulate task processing time.
System.Console.WriteLine("Continue With Method 1b completed.");
}
ContinueWith starts the next Task after the first finished.
So both your examples run synchroniously ( first methode A then methode b)
EDIT:
As an addition to your edit, your error is caused by the .Wait() function, which awaits the Task and returns void.
What's the difference with ContinueWith and without?
The title question of your post is very misleading. The use of ContinueWith() in your code examples is the least interesting difference. The much more significant difference is that the first example just calls the methods directly, while the second uses Task.Run().
Now, as it happens there would be no reason to write the code as in your second example. Even ignoring the ContinueWith() aspect, if all your task does is call a method, and all you're going to do with the task is synchronously wait on the task (i.e. call the Wait() method), then you might as well just call that method in your current thread. No need for Task.Run() in that situation.
Similarly, if all you're going to do with ContinueWith() is call another method immediately after, you might as well just call the method directly.
By blocking in the current thread, you've rendered useless any advantage there might have been in executing those two methods asynchronously.
Of course, there is a clear mechanical difference. You get the same results, ultimately, but how that result is achieved is very different. In the first example, you just call the methods, one after another. Each call executes in the current thread. In the second example, you are essentially asking the thread pool to execute each method in sequence, while you block the current thread waiting for that to happen.
It's similar to the difference between you peeling an onion and then chopping it yourself, and asking someone else to peel an onion and then chop it while you sit around twiddling your thumbs waiting for them to finish those actions.
Finally, as far as the error message you got, "Cannot implicitly convert type 'void' to 'System.Threading.Tasks.Task'", that only happened because you added the Task t variable and tried to set it to the result of the Wait() method. Since the Wait() method doesn't return anything (i.e. has a declared return type of void), never mind a value of Task, it's not possible to set the value of t using its return value. Hence the error message. If you want to assign a Task variable, you would need to just leave out the call to Wait():
Task t = Task.Run(() => ContinueWith_Method1a())
.ContinueWith(task => ContinueWith_Method1b());
Related
This question already has answers here:
When does 'await' immediately leave a method and when does it not?
(6 answers)
Closed 9 months ago.
After reading a lot about async/await I still have a fundamental question (that I kind of assume the answer but I just want confirmation).
Let's discuss over some code:
async Task methodA() {
//code A (without awaits or Task.Run)
Task.Run(()=> //code A' (without awaits or Task.Run))
}
async Task methodB() {
//code B (without awaits or Task.Run)
await methodA();
}
void Main() {
//code C (without awaits or Task.Run)
methodB(); (no await)
//code D (without awaits or Task.Run, no pun intended)
}
What I think will happen:
Run code C
Run code B
Run code A
Run code A' and code D (different threads, in parallel)
The doubt comes from what's in the documentation:
The await operator suspends evaluation of the enclosing async method
until the asynchronous operation represented by its operand completes. [...]
The await operator doesn't block the thread that evaluates the async method.
The key being here what represents an asynchronous operation. Cause considering this other piece of documentation:
The await operator tells the compiler that the async method can't
continue past that point until the awaited asynchronous process is
complete. In the meantime, control returns to the caller of the async
method.
One might think that, since methodA() is async, once methodB reaches the await methodA(), then it might return control to the caller and allow to run code D in parallel to code A and code A'.
The essence is if method A constitutes an asynchronous operation as described in the documentation, or only until it reaches truly async code (code that runs on another thread) then it actually allows control to return to the caller (which in this case is code A').
My understanding is that asynchronous operation is an operation that will run on another thread, is this correct? So things like Task.Run, Task.Delay, Task.Sleep..? And that even though code A is within an async method, it is not an async operation and control does not go immediately back when awaiting methodA. Is this correct?
Just for completion, check this question where in the answer's comments they argue precisely about this, without a very clear answer.
[...], control returns to the caller of the async method.
This sentence had confused the hell out of me when I was learning asynchronous programming. What it means is that the Task is created and returned. You can think the asynchronous methods as generators for Task objects. The async method has to do some work in order to create the Task. This work completes when the first await of an incomplete awaitable inside the method is reached. At that point the Task is created, it is handed to the caller of the method, and the caller can do whatever it wants with it.
Usually the caller awaits the task, but it can also do other things before awaiting it, or it might never await it and completely ignore it, although this is not recommended. Generally you want to keep track of your tasks, and not let them run unattended in a fire-and-forget fashion.
When the caller does not await immediately the returned task, and the task was not in a completed state upon creation, you introduce concurrency in your application: More than one things might be happening at overlapping time spans. You can read about the differences between concurrency and parallelism here.
I have a method that returns a List<> of an object. This method takes a while to run.
private List<MyObject> GetBigList()
{
... slow stuff
}
This method is called from 4 or 5 sources. So, I thought I would try and use async and await to keep things moving while this list builds. I added this method:
public async Task<List<MyObject>> GetBigListAsync()
{
var resultsTask = GetBigList();
var resuls = await resultsTask;
return resuls;
}
But, on this line:
var resuls = await resultsTask;
I get this error:
List<MyObject> does not contain a definition for GetAwaiter,
and no extension method 'GetAwaiter' accepting a first argument of type List<MyObject> could be found.
What am I missing?
It seems you're a newbee to async-await. What really helped me to understand what async-await does is the restaurant analogy given by Eric Lippert in this interview. Search somewhere in the middle for async await.
Here he describes that if a cook has to wait for something, instead of doing nothing he starts looking around to see if he can do something else in the meantime.
Async-await is similar. Instead of awaiting for a file to be read, a database query to return, a web page to be downloaded, your thread will go up the callstack to see if any of the callers are not awaiting and performs those statements until he sees an await. Once he sees the await the thread goes up the call stack again to see if one of the callers is not awaiting etc. After a while when the file is read, or the query is finished etc, the statements after the await are performed.
Normally while reading your big list your thread would be very busy instead of idly waiting. It's not certain that ordering another thread to do the stuff would improve the time needed to read your list. Consider measuring both methods.
One reason to use async-await, even if it would lengthen the time
needed to read the big list, would be to keep the caller (user
interface?) responsive.
To make your function async, you should do the following:
Declare the function async;
Instead of TResult return Task<TResult> and instead of void return Task;
If your function calls other async functions, consider remembering the returned task instead of await, do other useful stuff you need to do and await the task when you need the result;
If you really want to let another thread do the busy stuff. call
Task.Run( () => GetBigList())
and await when you need the results.
private async Task<List<MyObject>> GetBigListAsync()
{
var myTask = Task.Run( () => GetBigList());
// your thread is free to do other useful stuff right nw
DoOtherUsefulStuff();
// after a while you need the result, await for myTask:
List<MyObject> result = await myTask;
// you can now use the results of loading:
ProcessResult(result);
return result;
}
Once again: if you have nothing useful to do while the other thread is loading the List (like keeping UI responsive), don't do this, or at least measure if you are faster.
Other articles that helped me understanding async-await were
- Async await, by the ever so helpful Stephen Cleary,
- and a bit more advanced: Async-Wait best practices.
resultTask is just the list returned from GetBigList(), so nothing will happen async there.
What you can do is offload the task to a separate thread on the threadpool by using Task.Run and return the awaitable Task object:
// Bad code
public Task<List<MyObject>> GetBigListAsync()
{
return Task.Run(() => GetBigList());
}
While above example best matches what you were trying to do, it is not best practice. Try to make the GetBigList() async by nature or if there really is no way, leave the decision about executing the code on a separate thread to the calling code and don't hide this in the implementation F.e. if the calling code already runs async, there is no reason to spawn yet another thread. This article describes this in more detail.
A couple of years later but I feel it is worth to add for the collection, once people search for the resolution since .NET has changed quite a bit:
return await Task.FromResult(GetBigList())
I am just new to this world of asynchronous stuff.
Please bear with my lack of knowledge.
It is said when a method encounters await ... "It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method."
I did not get this part.
So does it mean the method still keeps on running synchronously and waits till the awaitable returns and then proceeds with the rest of the method?
If not please explain then why Task.Run is needed to run a method in the background or in a fire and forget manner. I could still be achieved via await also right? i.e.
The method keeps on executing the rest of the statements without waiting for the await to return.
I hope that is similar to a background run approach. Or is not it? I am confused.
If a method is marked with async and await and that in turn calls another method asynchronously in a separate layer that's also marked with async and await ..
then how the the call of the first method that's marked with async and await from a separate method say name ABC should look like?
I do not want to annotate that method to be async/await. So
Task.Run(() => DoWork());
from ABC () is fine without marking it async/await?
Or is it against the principle of asynchrony?
Here is what I am trying to achieve ...
public IList<CreateCaseOutput> ABC(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)
{
CaseSQL.getABCParameters(CreateCaseInput, RequestType, out strSPQuery, out listParam);
var AcctLst = rep.ExecuteStoredProcedure<CreateCaseOutput>(strSPQuery, listParam).ToList();
if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
{
Task.Run(async () =>
{
await DEF(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
}).ConfigureAwait(false);
}
console.writeLine("After Async called");
return AcctLst;
}
public async Task<SaveCaseSearchOutput>> DEF(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
CaseSQL.getDEFParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);
var AcctLst = await rep.ExecuteStoredProcedureAsync<SaveCaseSearchOutput>(strSPQuery, listParam);
return AcctLst;
}
DEF which is async/await needs to be called in the background in fire and forget approach from ABC and once fired I want to continue with rest of ABC and run DEF in the background. What's wrong in this fire and forget approach ? If I call
only
DEF(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
instead of
Task.Run(async () =>
{
await DEF(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
}).ConfigureAwait(false);
}
return AcctLst;
then this code runs synchronously in debugger.
Am I doing something wrong ?
So does it mean the method still keeps on running synchronously and waits till the awaitable returns and then proceeds with the rest of the method?
No. The awaitable has a "callback" mechanism. So, the method just registers itself with the awaitable. When the awaitable completes, it will execute its callbacks, which include the continuation of the async method.
In the meantime, the async method returns an incomplete task.
If not please explain then why Task.Run is needed to run a method in the background or in a fire and forget manner.
If you want to run on a background thread, then use Task.Run. Task.Run just schedules work to the thread pool.
I could still be achieved via await also right? i.e.
The method keeps on executing the rest of the statements without waiting for the await to return.
I hope that is similar to a background run approach. Or is not it? I am confused.
Well, you could "forget" the task by just not awaiting it:
MyMethod()
{
SomeMethodAsync(); // Note: no await; we just ignore the task.
}
You almost never want to do "fire and forget", though. Easily >90% of the time people ask for it, it's actually a design error.
I do not want to annotate that method to be async/await... Or is it against the principle of asynchrony?
That's against the principle. If you think about it, it doesn't really make sense to block on asynchronous code. You want to go through the trouble of making a method asynchronous (meaning it doesn't block a thread), and then block a thread on it? Why, exactly? Sometimes in practice, the code will temporarily end up in this kind of state during a transition to asynchronous code, but it's a tricky place to be.
For more information, see my article on async best practices, particularly "async all the way".
'It is said when a method encounters await ... "It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method."'
So let's say you have a method A that calls a method B. Method B has the "async" keyword in its declaration. In method B there is a time-consuming call to LongMethod, which ultimately returns a string.
What we want here is for method A to not have to wait for ages for method B's LongMethod to complete. So we write in Method B:
string newVariable = await Task.Run(()=>LongMethod());
If LongMethod itself is also async, then LongMethod can only return a void, a non generic Task or a generic Task. Therefore we would have to change the return type in the LongMethod declaration to Task<string>
So back to our story, the LongMethod task has started... At this point method A resumes from the next line of code after the call to method B, and method B continues to wait for the LongMethod to finish, so there are now two threads running. Eventually, the LongMethod completes and method B runs to the end, meanwhile method A has continued to run, or has maybe even finished running.
I hope this gives you a picture of the relationship between Async/Await and Tasks.
Now for question 2:
I think your question is basically asking if Method A in my example needs to be marked "async" because it makes a call to a method marked "async", and no it does not. Also please note that ABC() just needs to have
DoWork()
Not
Task.Run(() => DoWork());
ABC will then stop running until the DoWork method arrives at an 'await' statement.
If DoWork just needs to be run as its own task, and you don't want ABC() to stop at all, then just do
Task.Run(() => DoWork());
There is no benefit marking DoWork as async in this case, because there is no point having any await statements in DoWork.
I hope this helps, sorry if I've misinterpreted your questions!
From what you said in your comment (I'll assume you need the result in ABC)
You just need to write
Task<SaveCaseSearchOutput> t = Task.Run(() =>DEF(SaveCaseSearchInput,AcctLst.ElementAt(0).o_case_seq));
in ABC, instead of the current Task.Run call.
Then at the line in ABC when you require the result write
t.Wait();
SaveCaseSearchOutput g = t.Result;
DEF must remain async but you can remove the await statement in DEF.
In the following code, in the B method, the code Trace.TraceInformation("B - Started"); never gets called.
Should the method be running in parallel?
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
private static async Task A()
{
for (;;)
{
}
}
private static async Task B()
{
Trace.TraceInformation("B - Started");
}
static void Main(string[] args)
{
var tasks = new List<Task> { A(), B() };
Task.WaitAll(tasks.ToArray());
}
}
}
Short answer
No, as you wrote your two async methods, they are indeed not running in parallel. Adding await Task.Yield(); to your first method (e.g. inside the loop) would allow them to do so, but there are more reasonable and straightforward methods, highly depending on what you actually need (interleaved execution on a single thread? Actual parallel execution on multiple threads?).
Long answer
First of all, declaring functions as async does not inherently make them run asynchronously or something. It rather simplifies the syntax to do so - read more about the concepts here: Asynchronous Programming with Async and Await
Effectively A is not asynchronous at all, as there is not a single await inside its method body. Instructions up to the first use of await run synchronously like a regular method would.
From then on, the object that you await determines what happens next, i.e. the context that the remaining method runs in.
To force execution of a task to happen on another thread, use Task.Run or similar.
In this scenario, adding await Task.Yield() does the trick since the current synchronization context is null and this happens to indeed cause the task scheduler (should be ThreadPoolTaskScheduler) to execute the remaining instuctions on a thread-pool thread - some environment or configuration might cause you to only have one of them, so things would still not run in parallel.
Summary
The moral of the story is: Be aware of the differences between two concepts:
concurrency (which is enabled by using async/await reasonably) and
parallelism (which only happens when concurrent tasks get scheduled the right way or if you enforce it using Task.Run, Thread, etc. in which case the use of async is completely irrelevant anyway)
The async modifier is not a magic spawn-a-thread-here marker. It's sole purpose is to let the compiler know a method might depend on some asynchronous operation (A complex data-processing thread, I/O...) so it has to setup a state machine to coordinate the callbacks resulting from those asynchronous operations.
To make A run on another thread you would invoke it using Task.Run which wraps the invocation on a new thread with a Task object, which you can await. Be aware that await-ing a method does not mean your code runs in parallel to A's execution all by itself: It will until the very line you await the Task object, telling the compiler you need the value that the Task object returns. In this case await-ing Task.Run(A) will effectively make your program run forever, waiting for A to return, something that will never happen (barring computer malfunction).
Do have in mind that marking a method as async but not actually awaiting anything will only have the effect of a compiler warning. If you await something that is not truly async (It returns immediately on the calling thread with something like Task.FromResult) it will mean your program takes a runtime speed penalty. It is very slight, however.
No, the methods shown are not expected to "run in parallel".
Why B is never called - you have list of tasks tasks constructed via essentially series of .Add calls - and first is result of A() is added. Since the A method does not have any await it will run to the completion synchronously on the same thread. And after that B() would be called.
Now A will never complete (it is sitting in infinite loop) so really code will not even reach call to B.
Note that even if creation would succeed code never finish WaitAll as A still sits in infinite loop.
If you want methods to "run in parallel" you need to either run them implicitly/explicitly on new threads (i.e. with Task.Run or Thread.Start) or for I/O bound calls let method to release thread with await.
I have this line of code:
t.ContinueWith(_ => form.Close(),
TaskScheduler.FromCurrentSynchronizationContext());
...about which the compiler has this to say:
Warning 2 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
Now, this wasn't code that I wrote, but I thought that it's simply adding a continuation to the end of an existing task. I didn't think it's actually running the task (or the continuation). So surely this process of merely modifying the task is a synchronous operation? Why would I have to await it?
Why would I have to await it?
You don't have to await it, that's why it is a warning, not an error. But, if you're in an async method and you have a method that returns an awaitable object, most of the time, you shouldn't ignore it.
In normal synchronous code, you don't have to do anything special to wait until a method you called completes, each method call always blocks. But with asynchronous methods, you actually have to await them if you want to wait until they complete. Also, if the asynchronous operation fails and throws an exception, you won't know about it until you await the result of the method (or get the exception from the result some other way, such as calling Wait() if the awaitable is a Task).
So, if you ignore a returned awaitable value in an async method, it's likely that you have a bug in your code, which is what the warning is trying to avoid.
In your case, ContinueWith() returns a Task, which can be awaited, so the compiler assumes that you should await it. But in this case, you don't want to wait until the continuation completes and Close() most likely won't throw an exception. So, in this case, the warning is a false positive, it does not actually indicate a problem in the code.