I'm testing the async and I found this situation that I can't understand:
var watch = Stopwatch.StartNew();
var t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
var t2 = Task.Factory.StartNew(() =>
{
Task.Delay(1000);
return 1;
});
await Task.WhenAll(t1, t2);
var result = watch.ElapsedMilliseconds;
I would like to understand why the result is always 0! Why is not 1000, 2000 or the sum of the two tasks 3000? Why doesn't Task.WhenAll wait for the completion of the tasks?
Okay, so, the second one is the easy one, so let's handle that one.
For the second task, t2, you don't do anything with the result of Task.Delay(1000). You don't await it, you don't Wait it, etc. Given that the method is not async I supposed you meant for it to be a blocking wait. To do that you'd want to add Wait() to the end of the Delay call to make it a blocking wait, or just use Thread.Sleep().
For the first task, you're being bitten by the fact that you're using var. It's clearer what's happening when you don't use var:
Task<Task<int>> t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
You're returning a task of task of int, not just a Task of int. The outer task is "completed" as soon as the inner task finishes being started. When you use WhenAll you don't care about when the outer task finishes, you care about when the inner task finishes. There are a number of ways to handle this. One is to use Unwrap.
Task<int> t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
}).Unwrap();
Now you have your expected Task<int> and WhenAll will take at least 2000 milliseconds, as expected. You could also add in another await call to do the same thing:
Task<int> t1 = await Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
As mentioned by svick in a comment another option would be to just use Task.Run instead of StartNew. Task.Run has a special set of overloads for methods that take a Func<Task<T>> and return a Task<T> and automatically unwrap them for you:
Task<int> t1 = Task.Run(async () =>
{
await Task.Delay(2000);
return 2;
});
For this reason it's preferable to use Task.Run as the default option when you're creating async lambdas as it will "handle" this issue for you, although it's best to be aware of it for the complex cases where you can't use Task.Run.
Finally we come to the option that you didn't do, which is what you probably should be actually doing in this case. Since Task.Delay already returns a Task, there's no need to put it in StartNew in the first place. Rather than creating a nested task and using Unwrap you can just not wrap it in the first place:
var t3 = Task.Delay(3000);
await Task.WhenAll(t1, t2, t3);
If you actually just want to wait for a fixed amount of time that's what you should be doing.
Related
I have this construct in my main(), which creates
var tasks = new List<Task>();
var t = Task.Factory.StartNew(
async () =>
{
Foo.Fim();
await Foo.DoBar();
});
//DoBar not completed
t.Wait();
//Foo.Fim() done, Foo.DoBar should be but isn't
However, when I .Wait for t, it won't wait for the call to DoBar() to complete.
How do I get it to actually wait?
It's discouraged to use Task.Factory.StartNew with async-await, you should be using Task.Run instead:
var t = Task.Run(
async () =>
{
Foo.Fim();
await Foo.DoBar();
});
The Task.Factory.StartNew api was built before the Task-based Asynchronous Pattern (TAP) and async-await. It will return Task<Task> because you are starting a task with a lambda expression which happens to be async and so returns a task. Unwrap will extract the inner task, but Task.Run will implicitly do that for you.
For a deeper comparison, there's always a relevant Stephen Toub article: Task.Run vs Task.Factory.StartNew
It seems like I get desired functionality by Unwrap()ing the task.
I'm not quite sure I get the reasoning behind this, but I suppose it works.
var t = Task.Factory.StartNew(
async () =>
{
Foo.Fim();
await Foo.DoBar();
}).Unwrap();
edit: I've looked for ddescription of Unwrap():
Creates a proxy Task that represents the asynchronous operation of a Task<Task<T>>
I thought this was traditionally what the task did, but if I need to call unwrap I suppose that's fine.
I faced similar issue recently and figured out that all you need to do is have DoBar() return some value and use .Result instead of wait.
var g = Task.Run(() => func(arg));
var val = g.Result;
This will wait for func to return its output and assign it to val.
My goal was to start "Task2" after "Task1". At first I wrote code like "Code1" below, but it did not work (Task2 started before Task1 was finished). So I searched Stackoverflow and modified my code like "Code2" below as the existing answer suggested. I wonder why "Code1" did not work.
Code1
static void Main(string[] args)
{
var p = new Program();
p.Test2();
Console.ReadKey();
}
void Test2()
{
Task.Factory.StartNew(async () =>
{
await Task1();
}).ContinueWith((t) => {
Task2();
});
}
async Task Task1()
{
Debug.WriteLine("Task 1 starting....");
await LongTask();
Debug.WriteLine("Task 1 done");
}
Task LongTask()
{
return Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
});
}
void Task2()
{
Debug.WriteLine("Task 2");
}
Code2
Task.Factory.StartNew(async () =>
{
await Task1();
Task2();
}).ContinueWith((t) => {
//Task2();
});
Because when you are running task like Task.Factory.StartNew(async () => ... it returns Task<Task> (task of task). And first task terminates without waiting for the inner Task.
For preventing this situation, you can use Unwrap method:
Task.Factory.StartNew(async () =>
{
await Task1();
})
.Unwrap()
.ContinueWith((t) => {
Task2();
});
That StartNew will return Task<Task>, and it seems you want to execute continuation after inner task completion. That's why we need Unwrap.
It “unwraps” the inner task that’s returned as the result of the outer task. Calling Unwrap on a Task gives you back a new Task (which we often refer to as a proxy) which represents the eventual completion of the inner task. And then, we are adding continuation to the inner task.
But, as Task.Run will do that unwrapping automatically you can use Task.Run in that case:
Task.Run(async () =>
{
await Task1();
})
.ContinueWith((t) => {
Task2();
});
And that can be simplified to:
Task.Run(async () =>
{
await Task1();
Task2();
});
Detailed information about diferences between Task.Run and Task.Factory.StartNew:
Read more here from Stephen Toub who is an engineer in the .Net team. The reason of decision in case of Task.Run:
Because we expect it to be so common for folks to want to offload work
to the ThreadPool, and for that work to use async/await, we decided to
build this unwrapping functionality into Task.Run.
By the way, as Stephen recommended just try to use Task.Run in most cases, but this in no way obsoletes Task.Factory.StartNew, there is still some places in which Task.Factory.StartNew must be used:
Task.Factory.StartNew still has many important (albeit more advanced)
uses. You get to control TaskCreationOptions for how the task
behaves. You get to control the scheduler for where the task should
be queued to and run. You get to use overloads that accept object
state, which for performance-sensitive code paths can be used to avoid
closures and the corresponding allocations. For the simple cases,
though, Task.Run is your friend.
Task.Factory.StartNew don't understand async lambdas. For Task.Factory.StartNew your lambda is just function returning Task. It doesn't automatically await that task. Also, note that using Task.Factory.StarNew and ContinueWith is discouraged in modern C# as it hard to use correctly (please read, "StartNew is Dangerous" by Stephen Cleary). You should use Task.Factory.StarNew or ContinueWith only if you can't do without them.
Instead, you can just use async/await one more time:
async Task Test2()
{
await Task1();
Task2();
}
or Task.Run:
async Task Test2()
{
return Task.Run(await () =>
{
await Task1();
Task2();
});
}
The second approach might be convenient if you want to make sure that your asynchronous Task1() is started on background thread.
I've done this Unit Test and I don't understand why the "await Task.Delay()" doesn't wait !
[TestMethod]
public async Task SimpleTest()
{
bool isOK = false;
Task myTask = new Task(async () =>
{
Console.WriteLine("Task.BeforeDelay");
await Task.Delay(1000);
Console.WriteLine("Task.AfterDelay");
isOK = true;
Console.WriteLine("Task.Ended");
});
Console.WriteLine("Main.BeforeStart");
myTask.Start();
Console.WriteLine("Main.AfterStart");
await myTask;
Console.WriteLine("Main.AfterAwait");
Assert.IsTrue(isOK, "OK");
}
Here is the Unit Test output :
How is this possible an "await" doesn't wait, and the main thread continues ?
new Task(async () =>
A task does not take a Func<Task>, but an Action. It will call your asynchronous method and expect it to end when it returns. But it does not. It returns a task. That task is not awaited by the new task. For the new task, the job is done once the method returned.
You need to use the task that already exists instead of wrapping it in a new task:
[TestMethod]
public async Task SimpleTest()
{
bool isOK = false;
Func<Task> asyncMethod = async () =>
{
Console.WriteLine("Task.BeforeDelay");
await Task.Delay(1000);
Console.WriteLine("Task.AfterDelay");
isOK = true;
Console.WriteLine("Task.Ended");
};
Console.WriteLine("Main.BeforeStart");
Task myTask = asyncMethod();
Console.WriteLine("Main.AfterStart");
await myTask;
Console.WriteLine("Main.AfterAwait");
Assert.IsTrue(isOK, "OK");
}
The problem is that you are using the non-generic Task class, that is not meant to produce a result. So when you create the Task instance passing an async delegate:
Task myTask = new Task(async () =>
...the delegate is treated as async void. An async void is not a Task, it cannot be awaited, its exception cannot be handled, and it's a source of thousands of questions made by frustrated programmers here in StackOverflow and elsewhere. The solution is to use the generic Task<TResult> class, because you want to return a result, and the result is another Task. So you have to create a Task<Task>:
Task<Task> myTask = new Task<Task>(async () =>
Now when you Start the outer Task<Task> it will be completed almost instantly because its job is just to create the inner Task. You'll then have to await the inner Task as well. This is how it can be done:
myTask.Start(TaskScheduler.Default);
Task myInnerTask = await myTask;
await myInnerTask;
You have two alternatives. If you don't need an explicit reference to the inner Task then you can just await the outer Task<Task> twice:
await await myTask;
...or you can use the built-in extension method Unwrap that combines the outer and the inner tasks into one:
await myTask.Unwrap();
This unwrapping happens automatically when you use the much more popular Task.Run method that creates hot tasks, so the Unwrap is not used very often nowadays.
In case you decide that your async delegate must return a result, for example a string, then you should declare the myTask variable to be of type Task<Task<string>>.
Note: I don't endorse the use of Task constructors for creating cold tasks. As a practice is generally frowned upon, for reasons I don't really know, but probably because it is used so rarely that it has the potential of catching other unaware users/maintainers/reviewers of the code by surprise.
General advice: Be careful everytime you are supplying an async delegate as an argument to a method. This method should ideally expect a Func<Task> argument (meaning that understands async delegates), or at least a Func<T> argument (meaning that at least the generated Task will not be ignored). In the unfortunate case that this method accepts an Action, your delegate is going to be treated as async void. This is rarely what you want, if ever.
[Fact]
public async Task SimpleTest()
{
bool isOK = false;
Task myTask = new Task(() =>
{
Console.WriteLine("Task.BeforeDelay");
Task.Delay(3000).Wait();
Console.WriteLine("Task.AfterDelay");
isOK = true;
Console.WriteLine("Task.Ended");
});
Console.WriteLine("Main.BeforeStart");
myTask.Start();
Console.WriteLine("Main.AfterStart");
await myTask;
Console.WriteLine("Main.AfterAwait");
Assert.True(isOK, "OK");
}
Just want to know what is the order of the task result when using WhenAll and ContinueWith.
Are these results gurenteed to be in the same order with task Id?
I wrote below code
public static async Task<string> PrintNumber(int number)
{
return await Task.Delay(number*1000).ContinueWith(_=>
{
Console.WriteLine(number);return "TaskId:"+Task.CurrentId+" Result:"+number;
});
}
public static void Main()
{
Task.WhenAll(new[]
{
PrintNumber(3),
PrintNumber(2),
PrintNumber(1),
}).ContinueWith((antecedent) =>
{
foreach(var a in antecedent.Result)
{
Console.WriteLine(a);
}
});
}
and run that several times in linqpad getting the same result
1
2
3
TaskId:15 Result:3
TaskId:14 Result:2
TaskId:13 Result:1
or
1
2
3
TaskId:18 Result:3
TaskId:17 Result:2
TaskId:16 Result:1
With that specific invocation, the argument of a Task[] -- the order is not guaranteed.
In fact, according to the Task.WhenAll(Task[]) documentation there is no mention of order whatsoever. But if you use the Task.WhenAll(IEnumerable<Task<TResult>>) overload it reads as follows:
If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state. The Result of the returned task will be set to an array containing all of the results of the supplied tasks in the same order as they were provided (e.g. if the input tasks array contained t1, t2, t3, the output task's Result will return an TResult[] where arr[0] == t1.Result, arr1 == t2.Result, and arr[2] == t3.Result).
When you call Task.WhenAll (with either an enumerable or a params array), the order of the results match the order of the tasks passed to that method.
That is to say, this is true:
var task1 = PrintNumber(3);
var task2 = PrintNumber(2);
var task3 = PrintNumber(1);
var taskResults = await Task.WhenAll(task1, task2, task3);
// taskResults[0] is the same as task1.Result
// taskResults[1] is the same as task2.Result
// taskResults[2] is the same as task3.Result
However, ContinueWith is an entirely different story. ContinueWith attaches a continuation, and this continuation will run sometime after the task completes.
In your particular code, you're not attaching a continuation to the task passed to Task.WhenAll. But if you were, then that continuation could run anytime after that task completed.
On a side note, don't use ContinueWith (as I explain on my blog). Just use await instead; the resulting code is more correct, cleaner, and easier to maintain.
Task.Run(()=>{}) puts the action delegate into the queue and returns the task .
Is there any benefit of having async/await within the Task.Run()?
I understand that Task.Run() is required since if we want to use await directly, then the calling method will need to be made Async and will affect the calling places.
Here is the sample code which has async await within Task.Run(). The full sample is provided here: Create pre-computed tasks.
Task.Run(async () => { await new WebClient().DownloadStringTaskAsync("");});
Alternatively this could have been done:
Task.Run(() => new WebClient().DownloadStringTaskAsync("").Result;);
Since both, Task.Run() and Await will queue the work and will be picked by the thread pool, could the async/await within the Task.Run() be a bit redundant?
Is there any benefit of having async/await within the Task.Run() ?
Yes. Task.Run runs some action on a thread-pool thread. If such action does some IO work and asynchronously waits for the IO operation to complete via await, then this thread-pool thread can be used by the system for other work while the IO operation is still running.
Example:
Task.Run( async () =>
{
DoSomeCPUIntensiveWork();
// While asynchronously waiting for this to complete,
// the thread is given back to the thread-pool
var io_result = await DoSomeIOOperation();
DoSomeOtherCPUIntensiveWork(io_result);
});
Is there any benefit of having async/await within the Task.Run()
An async method returns to the caller as soon as the first await is hit (that operates on a non-completed task). So if that first execution "streak" of an async method takes a long time Task.Run will alter behavior: It will cause the method to immediately return and execute that first "streak" on the thread-pool.
This is useful in UI scenarios because that way you can make 100% sure that you are not blocking the UI. Example: HttpWebRequestdoes DNS resolution synchronously even when you use one of the async methods (this is basically a library bug/design error). This can pause the UI thread. So you can use Task.Run to be 100% sure that the UI is never blocked for longer than a few microseconds.
So back to the original question: Why await inside a Task.Run body? For the same reason you normally await: To unblock the thread.
In the example that you linked the main thread is being blocked until the asynchronous operation is done. It's being blocked by calling Wait() (which by the way is generally a bad idea).
Let's have a look at the return from the DownloadStringAsync in the linked sample:
return Task.Run(async () =>
{
content = await new WebClient().DownloadStringTaskAsync(address);
cachedDownloads.TryAdd(address, content);
return content;
});
Why would you wrap this in a Task? Think about your options for a second. If you don't want to wrap this in a Task, how would you make sure the method returns a Task<string> and still have it work? You'd mark the method as async of course! However, if you mark your method as async and you call Wait on it, you'll most likely end up with a deadlock, since the main thread is waiting for the work to finish, and your blocking the main thread so it can't let you know it's done.
When marking a method as async, the state machine will run on the calling thread, in your example however, the state machine runs on a separate thread, meaning there is little to no work being done on the main thread.
Calling Async from Non-Async Methods
We do some stuff like that when we are trying to call an async method inside of a non-async method. Especially if the async method is a known quantity. We use more of a TaskFactory though ... fits a pattern, makes it easier to debug, makes sure everyone takes the same approach (and -- gives us one throat to choke if async-->sync starts acting buggy).
So, Your Example
Imagine, in your example, that you have a non-async function. And, within that function, you need to call await webClient.DoSomethingAsync(). You can't call await inside of a function that's not async -- the compiler won't let you.
Option 1: Zombie Infestation
Your first option is to crawl all the way back up your call stack, marking every da*n method along the way as async and adding awaits everywhere. Everywhere. Like, everywhere. Then -- since all those methods are now async, you need to make the methods that reference them all async.
This, btw, is probably the approach many of the SO enthusiasts are going to advocate. Because, "blocking a thread is a bad idea."
So. Yeah. This "let async be async" approach means your little library routine to get a json object just reached out and touched 80% of the code. Who's going to call the CTO and let him know?
Option 2: Just Go with the One Zombie
OR, you can encapsulate your async inside of some function like yours...
return Task.Run(async () => {
content = await new WebClient().DoSomethingAsync();
cachedDownloads.TryAdd(address, content);
return content;
});
Presto... the zombie infestation has been contained to a single section of code. I'll leave it to the bit-mechanics to argue over how/why that gets executed at the CPU-level. I don't really care. I care that nobody has to explain to the CTO why the entire library should now be 100% async (or something like that).
Confirmed, wrapping await with Task.Run use 2 threads instead of one.
Task.Run(async () => { //thread #1
await new WebClient().DownloadStringTaskAsync(""); //thread #2
});
Say you have four calls wrapped like this, it will use 4 x 2 = 8 threads.
It would be better to just call these with simple await instead. For example:
Task<byte[]> t1 = new WebClient().DownloadStringTaskAsync("");
Task<byte[]> t2 = new WebClient().DownloadStringTaskAsync("");
byte[] t1Result = await t1;
byte[] t2Result = await t2;
Here is the proof that wrapped Task.Run are using extra threads. (Not using WebClient to prove the point)
private static async Task wrapped()
{
List<Task> tasks = new List<Task>();
tasks.AddRange(new []
{
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
await Task.WhenAll(tasks);
}
Unwrapped
private static async Task unwrapped()
{
List<Task> tasks = new List<Task>();
Task<int> t1 = new MyThread().RunMe();
Task<int> t2 = new MyThread().RunMe();
Task<int> t3 = new MyThread().RunMe();
Task<int> t4 = new MyThread().RunMe();
tasks.AddRange(new[] {t1, t2, t3, t4});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
int i1 = await t1;
int i2 = await t2;
int i3 = await t3;
int i4 = await t4;
}
Full POC code here
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncThreadDemo
{
class Program
{
static async Task Main(string[] args)
{
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"Init thread count: {number}");
//await wrapped();
await unwrapped();
number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"Done thread count: {number}");
Console.ReadLine();
}
private static async Task wrapped()
{
List<Task> tasks = new List<Task>();
tasks.AddRange(new []
{
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
await Task.WhenAll(tasks);
}
private static async Task unwrapped()
{
List<Task> tasks = new List<Task>();
Task<int> t1 = new MyThread().RunMe();
Task<int> t2 = new MyThread().RunMe();
Task<int> t3 = new MyThread().RunMe();
Task<int> t4 = new MyThread().RunMe();
tasks.AddRange(new[] {t1, t2, t3, t4});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
int i1 = await t1;
int i2 = await t2;
int i3 = await t3;
int i4 = await t4;
}
}
public class MyThread
{
public static int _counter;
public async Task<int> RunMe()
{
await Task.Run(() =>
{
for (int i = 0; i < 2; ++i)
{
Thread.Sleep(1000);
Console.WriteLine($"T{Thread.CurrentThread.ManagedThreadId} {i}");
}
Console.WriteLine($"T{Thread.CurrentThread.ManagedThreadId} done");
});
return _counter++;
}
}
}