This question already has answers here:
Await on a completed task same as task.Result?
(2 answers)
Closed 6 years ago.
I writing a small example to get value 5 in method TestMethod, I have 2 ways to do that:
static async Task<int> TestMethod()
{
await Task.Delay(0);
return 5;
}
static async Task Caller()
{
Task<int> test = TestMethod();
int i = await test;
Console.WriteLine("i: " + i);
int k = test.Result;
Console.WriteLine("k: " + k);
}
The output:
i: 5
k: 5
So, my questions are: what's the difference between await test and test.Result? And when to use await test/test.Result?
First version
static void Caller()
{
Task<int> test = TestMethod();
int k = test.Result;
Console.WriteLine("k: " + k);
}
In this version the async keyword would be obsolete. This is a synchronous method. The executing thread blocks at test.Result until the task has finished.
Second version
static async Task Caller()
{
Task<int> test = TestMethod();
int i = await test;
Console.WriteLine("i: " + i);
}
This is a (kind of) asynchronous version (it's not really asynchron, it's just a synchronous method run on a different thread). The difference to the first version is that the compiler builds a state machine for this.
So the control flow of the executing thread is returned to the caller of this method when await test is reached.
When the task has finished, the execution of this method is resumed at Console.WriteLine (or more precisely at the assignment to i).
For more information about what the compiler does you can read for example this.
The second version is useful if you have a longer running task that you need to execute from an UI. Since the control is returned to the caller while awaiting the task, the UI thread is not blocked and your application stays responsive.
Task.Result is equivalent to Task.Wait Method which blocks synchronously until the task is complete.
await on the other hand waits asynchronously till the task is completed.
If you can await is better.
Related
This question already has answers here:
Running multiple async tasks and waiting for them all to complete
(10 answers)
Closed 2 years ago.
I have a project to submit job to AWS state machine and monitor the job status. So I implement the code like following pseudo code:
Two tasks are calling in the main function:
public static void Main(string[] args)
{
ExeJobs("1").Wait();
MonitorJobs().Wait();
}
In MonitoryJobs task, do something like:
public static async Task MonitorJobs()
{
int retry = 0;
for (int i = 0; i < retry; i++)
{
// Check History event here if find job id. else keep looping;
....
}
}
In ExeJobs task, do something like:
public static async Task ExeJobs(string jobId)
{
await SubmitJob(jobId);
ExecutionStatus status = ExecutionStatus.RUNNING;
while (status == ExecutionStatus.RUNNING)
{
status = await MonitorJobStaus(jobId);
}
}
I expected the MonitorJobs() is a thread keep live till I find the job execute status when it's running ExeJobs(). However it looks the MonitorJobs() task cannot start before ExeJobs() finish its while(status == ExecutionStatus.RUNNING) loop.
I wish MonitorJobs() can be running during the while loop in the other task and it should be expected result since they are two threads.
Anyone knows what's wrong here? Thanks
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.
public static async Task Main(string[] args)
{
await ExeJobs("1");
await MonitorJobs();
}
Wait will block until the task is finished. Also How your program will behave will be depended on what actually is happening inside your async tasks. You can use Task.WhenAll (making your main method async):
public static async Task Main(string[] args)
{
await Task.WhenAll(ExeJobs, MonitorJobs);
}
This will start both tasks (assuming that ExeJobs is actually asynchronous) and wait until both finish.
So you need to understand that when you await something, execution in that scope stops until the task is completed. If you want to have the execution keep going without waiting for it to finish, you need to assign it to a task and you can wait for it to finish after.
public static async Task Main(string[] args)
{
// start ExeJobs task but don't wait for it to finish
var jobTasks = ExeJobs("1");
// start monitor task but don't wait for it to finish
var monitorTask = MonitorJobs();
// wait for both tasks to finish before returning
await Task.WhenAll(jobTasks, monitorTask);
}
In programs utilizing async-await, my understanding is like this:
an async method that IS NOT awaited will run in the background (?) and rest of the code will continue to execute before this non-awaited method finishes
an async method that IS awaited will wait until the method finishes before moving on to the next lines of code
The application below was written by me to check if the above statements are correct.
using System;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
DoJob();
var z = 3;
Console.ReadLine();
}
static async Task DoJob()
{
var work1 = new WorkClass();
var work2 = new WorkClass();
while (true)
{
await work1.DoWork(500);
await work2.DoWork(1500);
}
}
}
public class WorkClass
{
public async Task DoWork(int delayMs)
{
var x = 1;
await Task.Delay(delayMs);
var y = 2;
}
}
}
Here are some of my observations:
The DoJob(); call is not awaited. However, the debugger shows me that the code inside of DoJob is being executed, just as if it was a normal non-async method.
When code execution gets to await work1.DoWork(500);, I would think "OK, so maybe now the DoJob method will be left and var z = 3; will be executed? After all, 'await' should leave the method." In reality, it just goes into DoWork and doesn't leave DoJob - var z = 3; is still not executed.
Finally, when execution reaches await Task.Delay(delayMs);, DoJob is left, and the var z = 3; is reached. After that, code after the Delay is executed.
The things that I don't understand:
Why does await Task.Delay(delayMs); leave the DoJob method, but await work1.DoWork(500); does not?
I see that DoJob is executing normally. I thought it would be done in the background (maybe by one of the thread pool threads?). Looks like it could block the thread if it was some long-running method, am I right?
Why does await Task.Delay(delayMs); leave the DoJob method, but await work1.DoWork(500); does not?
Because this code:
await work1.DoWork(500);
is the same as this code:
var task = work1.DoWork(500);
await task;
So your code is calling the method first, and then awaiting the returned task. It's common to talk about await as "awaiting method calls", but that's not what actually happens - technically, the method call is done first (synchronously), and then the returned task is awaited.
I see that DoJob is executing normally. I thought it would be done in the background (maybe by one of the thread pool threads?).
No; with true asynchronous operations, there is no thread that is blocked on that operation.
Looks like it could block the thread if it was some long-running method, am I right?
Yes.
my understanding is like this
I recommend reading my async intro for a better mental framework. In summary:
async enables the await keyword. It also generates a state machine that handles creating the Task return value and stuff like that.
await operates on an "awaitable" (usually a task). First, it checks to see if it's already complete; if it is, the async method continues executing synchronously.
If the awaitable is not already complete, then await (by default) captures its context and schedules the continuation of the async method to run on that context when the awaitable completes.
The compiler splits the code in an async method in chunks. 1 before the first await and 1 between each await and 1 after the last await.
The execution will return to the caller at the first non completed awaiter or the end of the method.
This method will only return a completed Task after fully executed:
async Task M1() => await Task.CompletedTask;
This method will only return an incomplete Task that will complete when the Task returned by Task.Dealy(1000) is completed:
async Task M2() => await Task.Delay(1000);
Here's a small example:
static async Task Main(string[] args)
{
var t = TwoAwaits();
Console.WriteLine("Execution returned to main");
await t;
}
private static async Task TwoAwaits()
{
Console.WriteLine("Before awaits");
await Task.CompletedTask;
Console.WriteLine("Between awaits #1");
await Task.Delay(1000);
Console.WriteLine("Between awaits #2");
await Task.Delay(1000);
Console.WriteLine("After awaits");
}
/*
Before awaits
Between awaits #1
Execution returned to main
Between awaits #2
After awaits
*/
Let's look at the four possibilities:
(1)
void Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static async Task DoJob()
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
}
This outputs:
Main 0 - 14
DoJob 0 - 14
DoJob 1 - 14
Main 1 - 14
It has a 2 second pause after DoJob 0.
(2)
async Task Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
await DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static async Task DoJob()
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
}
Again this outputs:
Main 0 - 14
DoJob 0 - 14
DoJob 1 - 14
Main 1 - 14
(3)
async Task Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
await DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static Task DoJob()
{
return Task.Run(() =>
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
});
}
This has different output because it has changed thread:
Main 0 - 15
DoJob 0 - 13
DoJob 1 - 13
Main 1 - 13
And finally:
async Task Main()
{
Console.WriteLine($"Main 0 - {Thread.CurrentThread.ManagedThreadId}");
DoJob();
Console.WriteLine($"Main 1 - {Thread.CurrentThread.ManagedThreadId}");
}
public static Task DoJob()
{
return Task.Run(() =>
{
Console.WriteLine($"DoJob 0 - {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(2000);
Console.WriteLine($"DoJob 1 - {Thread.CurrentThread.ManagedThreadId}");
});
}
This has a different output again:
Main 0 - 13
Main 1 - 13
DoJob 0 - 12
DoJob 1 - 12
In this last case it is not waiting for DoJob because DoJob is running on a different thread.
So if you follow the logic here the issue is that async/await doesn't create (or use) a different thread. The method called must do that.
Before Async & Await, there was two type of methods. Those who returned the result directly, and those who received a callback function as a parameter. On the latter, the method was invoked in the same thread syncronously and returned no value, and later, on the same or different thread your callback function would have been called with the result. Historically all I/O (disk, network, even memory) worked with callbacks (actually: interrupts) but medium to high level languages like C# would mask all that internally so end users don't need to learn/write low level code.
This worked pretty well up to a point, except this optimization wasted some physical resources. For example Node.js outperformed several other languages/server platforms by their limitation that forces the developers to use the callback model instead of the 'managed' mode.
This pushed C# and other languages to go back to the callback model, but the code readability really suffered (code callback spaguetti). So Async and Await was introduced.
Async and await let's you write in the 'callback model' with 'managed' syntax. All callbacks are handled by the compiler.
Each time you write 'await' in an async method, your method is actually split into two methods connected by a callback.
Now, you can write an async method that does regular sync code, without awaits, nor thread switch or I/O. That 'async' method will actually run synchronously. So, it is actually the same to await method1() or call without await. Why? because your async call is not awaiting anything, so your async code is still one piece of continous code.
If inside your method you await one, two or more different methods, then your method will be split into one, two or more pieces. And only the first piece will be guaranteed to be run synchronously. All the other pieces will run on other thread depending on the code that you are awaiting.
TL;DR;
Async/Await method is does not guarantees multi-threading or parallel processing. That will actually depend on the payload (the called async method). For example, http downloads will tipically be paralellized if you manage your awaits because those are functions that are mostly waiters of an external response. On the other side, heavy CPU processing, like compressing a file, will require other form of cpu/thread management not provided by async/await.
If you do not await an async method, your code will surely run synchronously up to the first await of the called method, given it has one. But later on, it may or not run sync.
why does await Task.Delay(delayMs); leave the DoJob method, but await work1.DoWork(500); does not?
Because, up and until there is an actual asynchronous call, it's still in the same context. If DoWork was just:
public async Task DoWork(int delayMs)
{
var x = 1;
var y = 2;
return Task.CompletedTask;
}
there would be no need for a continuation and hence, you would debug all the way without "jumping" back to the orignal await call.
Here is how your application could be remodeled if you were forced to avoid async/await for some reason. See how complex it gets to replicate the logic inside the loop. Async/await is really a gift from the heavens!
using System;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static Task Main(string[] args)
{
Console.WriteLine("Hello World!");
DoJob();
var z = 3;
Console.ReadLine();
return Task.CompletedTask;
}
static Task DoJob()
{
var work1 = new WorkClass();
var work2 = new WorkClass();
var tcs = new TaskCompletionSource<bool>();
Loop();
return tcs.Task;
void Loop()
{
work1.DoWork(500).ContinueWith(t1 =>
{
if (t1.IsFaulted) { tcs.SetException(t1.Exception); return; }
work2.DoWork(1500).ContinueWith(t2 =>
{
if (t2.IsFaulted) { tcs.SetException(t2.Exception); return; }
if (true) { Loop(); } else { tcs.SetResult(true); }
// The 'if (true)' corresponds to the 'while (true)'
// of the original code.
});
});
}
}
}
public class WorkClass
{
public Task DoWork(int delayMs)
{
var x = 1;
int y;
return Task.Delay(delayMs).ContinueWith(t =>
{
if (t.IsFaulted) throw t.Exception;
y = 2;
});
}
}
}
This question already has answers here:
Parallel.ForEach and async-await [duplicate]
(4 answers)
Parallel foreach with asynchronous lambda
(10 answers)
Closed 12 days ago.
I was reading this post about Parallel.ForEach where it was stated that "Parallel.ForEach is not compatible with passing in a async method."
So, to check I write this code:
static async Task Main(string[] args)
{
var results = new ConcurrentDictionary<string, int>();
Parallel.ForEach(Enumerable.Range(0, 100), async index =>
{
var res = await DoAsyncJob(index);
results.TryAdd(index.ToString(), res);
});
Console.ReadLine();
}
static async Task<int> DoAsyncJob(int i)
{
Thread.Sleep(100);
return await Task.FromResult(i * 10);
}
This code fills in the results dictionary concurrently.
By the way, I created a dictionary of type ConcurrentDictionary<string, int> because in case I have ConcurrentDictionary<int, int> when I explore its elements in debug mode I see that elements are sorted by the key and I thought that elenents was added consequently.
So, I want to know is my code is valid? If it "is not compatible with passing in a async method" why it works well?
This code works only because DoAsyncJob isn't really an asynchronous method. async doesn't make a method work asynchronously. Awaiting a completed task like that returned by Task.FromResult is synchronous too. async Task Main doesn't contain any asynchronous code, which results in a compiler warning.
An example that demonstrates how Parallel.ForEach doesn't work with asynchronous methods should call a real asynchronous method:
static async Task Main(string[] args)
{
var results = new ConcurrentDictionary<string, int>();
Parallel.ForEach(Enumerable.Range(0, 100), async index =>
{
var res = await DoAsyncJob(index);
results.TryAdd(index.ToString(), res);
});
Console.WriteLine($"Items in dictionary {results.Count}");
}
static async Task<int> DoAsyncJob(int i)
{
await Task.Delay(100);
return i * 10;
}
The result will be
Items in dictionary 0
Parallel.ForEach has no overload accepting a Func<Task>, it accepts only Action delegates. This means it can't await any asynchronous operations.
async index is accepted because it's implicitly an async void delegate. As far as Parallel.ForEach is concerned, it's just an Action<int>.
The result is that Parallel.ForEach fires off 100 tasks and never waits for them to complete. That's why the dictionary is still empty when the application terminates.
An async method is one that starts and returns a Task.
Your code here
Parallel.ForEach(Enumerable.Range(0, 100), async index =>
{
var res = await DoAsyncJob(index);
results.TryAdd(index.ToString(), res);
});
runs async methods 100 times in parallel. That's to say it parallelises the task creation, not the whole task. By the time ForEach has returned, your tasks are running but they are not necessarily complete.
You code works because DoAsyncJob() not actually asynchronous - your Task is completed upon return. Thread.Sleep() is a synchronous method. Task.Delay() is its asynchronous equivalent.
Understand the difference between CPU-bound and I/O-bound operations. As others have already pointed out, parallelism (and Parallel.ForEach) is for CPU-bound operations and asynchronous programming is not appropriate.
If you already have asynchronous work, you don't need Parallel.ForEach:
static async Task Main(string[] args)
{
var results = await new Task.WhenAll(
Enumerable.Range(0, 100)
Select(i => DoAsyncJob(I)));
Console.ReadLine();
}
Regarding your async job, you either go async all the way:
static async Task<int> DoAsyncJob(int i)
{
await Task.Delay(100);
return await Task.FromResult(i * 10);
}
Better yet:
static async Task<int> DoAsyncJob(int i)
{
await Task.Delay(100);
return i * 10;
}
or not at all:
static Task<int> DoAsyncJob(int i)
{
Thread.Sleep(100);
return Task.FromResult(i * 10);
}
Let's assume I have these methods:
public async Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
return await service.GetAsync();
}
and
public Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
return service.GetAsync();
}
Both options compile and work the same way. Is there any best practise as to which option is better of if one is faster then the other?
Or is it just some syntactic sugar?
In the first method compiler will generate "state machine" code around it and execution will be returned to the line return await service.GetAsync(); after task will be completed. Consider example below:
public async Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
// Here execution returns to the caller and returned back only when Task is completed.
Something value = await service.GetAsync();
DoSomething();
return value;
}
The line DoSomething(); will be executed only after service.GetAsync task is completed.
Second approach simply starts execution of service.GetAsync and return correspondent Task to the caller without waiting for completion.
public Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
Task<Something> valueTask = service.GetAsync();
DoSomething();
return valueTask;
}
So in the example above DoSomething() will be executed straight after line Task<Something> valueTask = service.GetAsync(); without waiting for completion of task.
Executing async method on the another thread depend on the method itself.
If method execute IO operation, then another thread will be only waste of the thread, which do nothing, only waiting for response. On my opinion async - await are perfect approach for IO operations.
If method GetAsync contains for example Task.Run then execution goes to the another thread fetched from thread pool.
Below is short example, not a good one, but it show the logic a tried to explain:
static async Task GetAsync()
{
for(int i = 0; i < 10; i++)
{
Console.WriteLine($"Iterate GetAsync: {i}");
await Task.Delay(500);
}
}
static Task GetSomethingAsync() => GetAsync();
static void Main(string[] args)
{
Task gettingSomethingTask = GetSomethingAsync();
Console.WriteLine("GetAsync Task returned");
Console.WriteLine("Start sleeping");
Thread.Sleep(3000);
Console.WriteLine("End sleeping");
Console.WriteLine("Before Task awaiting");
gettingSomethingTask.Wait();
Console.WriteLine("After Task awaited");
Console.ReadLine();
}
And output will be next:
Iterate GetAsync: 0
GetAsync Task returned
Start sleeping
Iterate GetAsync: 1
Iterate GetAsync: 2
Iterate GetAsync: 3
Iterate GetAsync: 4
Iterate GetAsync: 5
End sleeping
Before Task awaiting
Iterate GetAsync: 6
Iterate GetAsync: 7
Iterate GetAsync: 8
Iterate GetAsync: 9
After Task awaited
As you can see executing of GetAsync starts straight after calling it.
If GetSomethingAsync() will be changed to the:
static Task GetSomethingAsync() => new Task(async () => await GetAsync());
Where GetAsync wrapped inside another Task, then GetAsync() will not be executed at all and output will be:
GetAsync Task returned
Start sleeping
End sleeping
Before Task awaiting
After Task awaited
Of course you will need to remove line gettingSomethingTask.Wait();, because then application just wait for task which not even started.
This question already has answers here:
Difference between returning and awaiting a Task in an async method [duplicate]
(3 answers)
Closed 8 years ago.
Suppose I have below code:
static void Main(string[] args)
{
println("begin s");
Task<int> s = CaculateSometingAsync();
println("begin s1");
Task<int> s1 = CaculateSometingAsync1();
println(s.Result.ToString());
println(s1.Result.ToString());
}
static async Task<int> CaculateSometingAsync()
{
return await Task.Factory.StartNew<int>(() =>
{
Thread.Sleep(1000);
return 100;
});
}
static Task<int> CaculateSometingAsync1()
{
return Task.Factory.StartNew<int>(() =>
{
Thread.Sleep(1000);
return 200;
});
}
The result is as follow:
16:55:38 begin s
16:55:38 begin s1
16:55:39 100
16:55:39 200
What I know about these two functions is that they have the same behavior.
Both they create one thread-pool thread to run the task.
Both
Task<int> s = CaculateSometingAsync();
and
Task<int> s1 = CaculateSometingAsync1();
don't block the main thread.
So is there any difference between this two functions?
The difference is the way you're using it.
In the first one (CaculateSometingAsync) you're declaring it as asynchronous, and then you await inside it until it's done. You then return whatever it returns.
In your second one (CaculateSometingAsync1) you just use it as a "fire and forget" kind of things, so it goes away, waits, and returns straightto where you called it from.
(and why do you use a method println to print the string ? :) )
you await inside the CaculateSometingAsync but could await on s as the method is declared async, where as you could not await on s1 as CaculateSometingAsync1 is not declared async. The way you are using the keywords means there is no difference in bahviour