I'm trying to play a bit with C#'s async/await/continuewith.
My goal is to have to have 2 tasks which are running in parallel, though which task is executing a sequence of action in order.
To do that, I planned to have a List<Task> that represent the 2 (or more) tasks running in parallel, and to use ContinueWith on each of the Task
My problem is that the callback in continue with seems not to be executed while the await taskList has already returned.
In order to summarize, here's a sample to illustrate what I'm expecting to happen:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static void Main(string[] args)
{
Test().ContinueWith(
async (task) =>
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
},
TaskContinuationOptions.AttachedToParent).Wait();
Console.WriteLine("Done with test");
}
}
The expected output would be
Enter Test
Leave Test
Enter callback
Leave callback
Done with test
However, the output is
Enter Test
Leave Test
Enter callback
Done with test
Is there a way to make the Task on which ContinueWith is called wait for the provided function to complete before being considered as done? ie. .Wait will wait for both tasks to be completed, the original one, and the one which is returned by ContinueWith
When chaining multiple tasks using the ContinueWith method, your return type will be Task<T> whereas T is the return type of the delegate/method passed to ContinueWith.
As the return type of an async delegate is a Task, you will end up with a Task<Task> and end up waiting for the async delegate to return you the Task which is done after the first await.
In order to correct this behaviour, you need to use the returned Task, embedded in your Task<Task>. Use the Unwrap extension method to extract it.
When you're doing async programming, you should strive to replace ContinueWith with await, as such:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task MainAsync()
{
await Test();
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static void Main(string[] args)
{
MainAsync().Wait();
Console.WriteLine("Done with test");
}
}
The code using await is much cleaner and easier to maintain.
Also, you should not use parent/child tasks with async tasks (e.g., AttachedToParent). They were not designed to work together.
I'd like to add my answer to complement the answer which has already been accepted. Depending on what you're trying to do, often it's possible to avoid the added complexity of async delegates and wrapped tasks. For example, your code could be re-factored like this:
class Program
{
static async Task Test1()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task Test2()
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static async Task Test()
{
await Test1(); // could do .ConfigureAwait(false) if continuation context doesn't matter
await Test2();
}
static void Main(string[] args)
{
Test().Wait();
Console.WriteLine("Done with test");
}
}
Related
Why is the following example blocking? I was expecting "Run First" to run immediately and then 5 seconds later the "Run Last" would appear.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// Call SomeAsyncCode() somehow
SomeAsyncCode().GetAwaiter().GetResult();
Console.WriteLine("Run First");
}
private static async Task SomeAsyncCode()
{
// Use await here!
await Task.Delay(5000);
Console.WriteLine("Run Last");
// Other async goodness...
}
}
}
You are awaiting (term used loosely) the task.
It would make more sense if you didn't use .GetAwaiter().GetResult(); (which are internal framework methods anyway) and just wrote
SomeAsyncCode().Wait();
Console.WriteLine("Run First");
It then becomes obvious whats happening, you are waiting for the task to complete.
The following is probably more like what you expect;
// start task
var task = SomeAsyncCode();
Console.WriteLine("Run First");
task.Wait();
In all honesty though, it should be rare to need to call, Wait, Result or GetAwaiter().GetResult() on an async method, doing so in a UI app, or something with a Synchronization Context will likely cause a deadlock
Ideally you let async and await propagate, in C# 7.1 and higher you have the ability to create an async Entry Point which allows you use the Async and Await Pattern in a more succinct manner
static async Task Main(string[] args)
{
await SomeAsyncCode();
Console.WriteLine("Run First");
}
or
static async Task Main(string[] args)
{
var task = SomeAsyncCode();
Console.WriteLine("Run First");
await Task.WhenAll(task);
}
When you define async Task Method() - you are telling that this method should be awaited even though it will return nothing.
When you define async void Method() - you are telling that this is fire'n'forget method and you don't want to await it.
Also, when you void Main(string[] args) is returning - your application is closing and GC will kill all your tasks.
So, your code should be more like this:
static void Main(string[] args)
{
// Call SomeAsyncCode() somehow
SomeAsyncCode();
Console.WriteLine("Run First");
Console.ReadKey(); // you need this to prevent app from closing
}
private static async void SomeAsyncCode()
{
// Use await here!
await Task.Delay(5000);
Console.WriteLine("Run Last");
// Other async goodness...
}
I'm trying to play a bit with C#'s async/await/continuewith.
My goal is to have to have 2 tasks which are running in parallel, though which task is executing a sequence of action in order.
To do that, I planned to have a List<Task> that represent the 2 (or more) tasks running in parallel, and to use ContinueWith on each of the Task
My problem is that the callback in continue with seems not to be executed while the await taskList has already returned.
In order to summarize, here's a sample to illustrate what I'm expecting to happen:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static void Main(string[] args)
{
Test().ContinueWith(
async (task) =>
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
},
TaskContinuationOptions.AttachedToParent).Wait();
Console.WriteLine("Done with test");
}
}
The expected output would be
Enter Test
Leave Test
Enter callback
Leave callback
Done with test
However, the output is
Enter Test
Leave Test
Enter callback
Done with test
Is there a way to make the Task on which ContinueWith is called wait for the provided function to complete before being considered as done? ie. .Wait will wait for both tasks to be completed, the original one, and the one which is returned by ContinueWith
When chaining multiple tasks using the ContinueWith method, your return type will be Task<T> whereas T is the return type of the delegate/method passed to ContinueWith.
As the return type of an async delegate is a Task, you will end up with a Task<Task> and end up waiting for the async delegate to return you the Task which is done after the first await.
In order to correct this behaviour, you need to use the returned Task, embedded in your Task<Task>. Use the Unwrap extension method to extract it.
When you're doing async programming, you should strive to replace ContinueWith with await, as such:
class Program
{
static public async Task Test()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task MainAsync()
{
await Test();
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static void Main(string[] args)
{
MainAsync().Wait();
Console.WriteLine("Done with test");
}
}
The code using await is much cleaner and easier to maintain.
Also, you should not use parent/child tasks with async tasks (e.g., AttachedToParent). They were not designed to work together.
I'd like to add my answer to complement the answer which has already been accepted. Depending on what you're trying to do, often it's possible to avoid the added complexity of async delegates and wrapped tasks. For example, your code could be re-factored like this:
class Program
{
static async Task Test1()
{
System.Console.WriteLine("Enter Test");
await Task.Delay(100);
System.Console.WriteLine("Leave Test");
}
static async Task Test2()
{
System.Console.WriteLine("Enter callback");
await Task.Delay(1000);
System.Console.WriteLine("Leave callback");
}
static async Task Test()
{
await Test1(); // could do .ConfigureAwait(false) if continuation context doesn't matter
await Test2();
}
static void Main(string[] args)
{
Test().Wait();
Console.WriteLine("Done with test");
}
}
I copied below code from this link.But when I am compiling this code I am getting an entry point cannot be marked with the 'async' modifier. How can I make this code compilable?
class Program
{
static async void Main(string[] args)
{
Task<string> getWebPageTask = GetWebPageAsync("http://msdn.microsoft.com");
Debug.WriteLine("In startButton_Click before await");
string webText = await getWebPageTask;
Debug.WriteLine("Characters received: " + webText.Length.ToString());
}
private static async Task<string> GetWebPageAsync(string url)
{
// Start an async task.
Task<string> getStringTask = (new HttpClient()).GetStringAsync(url);
// Await the task. This is what happens:
// 1. Execution immediately returns to the calling method, returning a
// different task from the task created in the previous statement.
// Execution in this method is suspended.
// 2. When the task created in the previous statement completes, the
// result from the GetStringAsync method is produced by the Await
// statement, and execution continues within this method.
Debug.WriteLine("In GetWebPageAsync before await");
string webText = await getStringTask;
Debug.WriteLine("In GetWebPageAsync after await");
return webText;
}
// Output:
// In GetWebPageAsync before await
// In startButton_Click before await
// In GetWebPageAsync after await
// Characters received: 44306
}
The error message is exactly right: the Main() method cannot be async, because when Main() returns, the application usually ends.
If you want to make a console application that uses async, a simple solution is to create an async version of Main() and synchronously Wait() on that from the real Main():
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
// your async code here
}
This is one of the rare cases where mixing await and Wait() is a good idea, you shouldn't usually do that.
Update: Async Main is supported in C# 7.1.
Starting from C# 7.1 there are 4 new signatures for Main method which allow to make it async(Source, Source 2, Source 3):
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
You can mark your Main method with async keyword and use await inside Main:
static async Task Main(string[] args)
{
Task<string> getWebPageTask = GetWebPageAsync("http://msdn.microsoft.com");
Debug.WriteLine("In startButton_Click before await");
string webText = await getWebPageTask;
Debug.WriteLine("Characters received: " + webText.Length.ToString());
}
C# 7.1 is available in Visual Studio 2017 15.3.
I'm using C# 8 and its working fine.
static async Task Main(string[] args)
{
var response = await SomeAsyncFunc();
Console.WriteLine("Async response", response);
}
OR without "await" keyword.
static void Main(string[] args)
{
var response = SomeAsyncFunc().GetAwaiter().GetResult();
Console.WriteLine("Async response", response);
}
The difference between the code in the link's example and yours, is that you're trying to mark the Main() method with an async modifier - this is not allowed, and the error says that exactly - the Main() method is the "entry point" to the application (it's the method that is executed when your application starts), and it's not allowed to be async.
Wrap your async code in MainAsync() - which is an async function
then call MainAsync().GetAwaiter().GetResult();
I am trying to learn the async and await features of .NET 4.5 .First of all here's my code
static async void Method()
{
await Task.Run(new Action(DoSomeProcess));
Console.WriteLine("All Methods have been executed");
}
static void DoSomeProcess()
{
System.Threading.Thread.Sleep(3000);
}
static void Main(string[] args)
{
Method();
//Console.WriteLine("Method Started");
Console.ReadKey();
}
This code doesn't give me any results on the console. I cant understand why. I mean aren't tasks suppose be just threads that aren't blocking. However if i uncomment the Console.WriteLine() in the main method everything seems to be working fine.
Can anybody tell me what's going on here ?
With the async/await pattern some things are different as previously with threads.
you shouldn't use System.Threading.Thread.Sleep
because this is still blocking and does not work with async.
Instead use Task.Delay
Consider making all your code async. Only the Main method in your console cannot be async of cause
Avoid async void methods. Basically async void is just meant for event handlers which cannot return something. All other async methods should return Task or Task<T>
Modified your example:
static async Task Method()
{
await DoSomeProcess();
Console.WriteLine("All Methods have been executed");
}
static async Task DoSomeProcess()
{
await Task.Delay(3000);
}
Now change your Main method because this should be the place where you start your task
Task.Run(() => Method()).Wait();
//Console.WriteLine("Method Started");
Console.ReadKey();
There is a small learning curve to learn how to use the async and await keywords correctly..
The problem is that nobody waits whom is waiting, there are some other details such as the SyncronizationContext and Task:
you should check some articles:
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
To use async and await keywords in Console, you need an extra code:
Can't specify the 'async' modifier on the 'Main' method of a console app or
Await a Async Void method call for unit testing or Unit Test Explorer does not show up Async Unit Tests for metro apps
I usually do this approach:
static void Main(string[] args)
{
Console.WriteLine("HELLO WORLD");
var t1 = Task.Factory.StartNew(new Func<Task>(async () => await Method()))
.Unwrap();
Console.WriteLine("STARTED");
t1.Wait();
Console.WriteLine("COMPLETED");
Console.ReadKey();
}
static async Task Method()
{
// this method is perfectly safe to use async / await keywords
Console.WriteLine("BEFORE DELAY");
await Task.Delay(1000);
Console.WriteLine("AFTER DELAY");
}
I'm starting to learn about async / await in C# 5.0, and I don't understand it at all. I don't understand how it can be used for parallelism. I've tried the following very basic program:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Task task1 = Task1();
Task task2 = Task2();
Task.WaitAll(task1, task2);
Debug.WriteLine("Finished main method");
}
public static async Task Task1()
{
await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
Debug.WriteLine("Finished Task2");
}
}
}
This program just blocks on the call to Task.WaitAll() and never finishes, but I am not understanding why. I'm sure I'm just missing something simple or just don't have the right mental model of this, and none of the blogs or MSDN articles that are out there are helping.
I recommend you start out with my intro to async/await and follow-up with the official Microsoft documentation on TAP.
As I mention in my intro blog post, there are several Task members that are holdovers from the TPL and have no use in pure async code. new Task and Task.Start should be replaced with Task.Run (or TaskFactory.StartNew). Similarly, Thread.Sleep should be replaced with Task.Delay.
Finally, I recommend that you do not use Task.WaitAll; your Console app should just Wait on a single Task which uses Task.WhenAll. With all these changes, your code would look like:
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
public static async Task MainAsync()
{
Task task1 = Task1();
Task task2 = Task2();
await Task.WhenAll(task1, task2);
Debug.WriteLine("Finished main method");
}
public static async Task Task1()
{
await Task.Delay(5000);
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Delay(10000);
Debug.WriteLine("Finished Task2");
}
}
Understand C# Task, async and await
C# Task
Task class is an asynchronous task wrapper. Thread.Sleep(1000) can stop a thread running for 1 second. While Task.Delay(1000) won't stop the current work. See code:
public static void Main(string[] args){
TaskTest();
}
private static void TaskTest(){
Task.Delay(5000);
System.Console.WriteLine("task done");
}
When running," task done" will show up immediately. So I can assume that every method from Task should be asynchronous. If I replace TaskTest () with Task.Run(() =>TaskTest()) task done won't show up at all until I append a Console.ReadLine(); after the Run method.
Internally, Task class represent a thread state In a State Machine. Every state in state machine have several states such as Start, Delay, Cancel, and Stop.
async and await
Now, you may wondering if all Task is asynchronous, what is the purpose of Task.Delay ? next, let's really delay the running thread by using async and await
public static void Main(string[] args){
TaskTest();
System.Console.WriteLine("main thread is not blocked");
Console.ReadLine();
}
private static async void TaskTest(){
await Task.Delay(5000);
System.Console.WriteLine("task done");
}
async tell caller, I am an asynchronous method, don't wait for me. await inside the TaskTest() ask for waiting for the asynchronous task. Now, after running, program will wait 5 seconds to show the task done text.
Cancel a Task
Since Task is a state machine, there must be a way to cancel the task while task is in running.
static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static void Main(string[] args){
TaskTest();
System.Console.WriteLine("main thread is not blocked");
var input=Console.ReadLine();
if(input=="stop"){
tokenSource.Cancel();
System.Console.WriteLine("task stopped");
}
Console.ReadLine();
}
private static async void TaskTest(){
try{
await Task.Delay(5000,tokenSource.Token);
}catch(TaskCanceledException e){
//cancel task will throw out a exception, just catch it, do nothing.
}
System.Console.WriteLine("task done");
}
Now, when the program is in running, you can input "stop" to cancel the Delay task.
Your tasks never finish because they never start running.
I would Task.Factory.StartNew to create a task and start it.
public static async Task Task1()
{
await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
Debug.WriteLine("Finished Task2");
}
As a side note, if you're really just trying to pause in a async method, there's no need to block an entire thread, just use Task.Delay
public static async Task Task1()
{
await Task.Delay(TimeSpan.FromSeconds(5));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Delay(TimeSpan.FromSeconds(10));
Debug.WriteLine("Finished Task2");
}
Async and await are markers which mark code positions from where control should resume after a task (thread) completes.
Here's a detail youtube video which explains the concept in a demonstrative manner http://www.youtube.com/watch?v=V2sMXJnDEjM
If you want you can also read this coodeproject article which explains the same in a more visual manner.
http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:-“Async”and“Await”(Codemarkers)
static void Main(string[] args)
{
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "Main";
Console.WriteLine(Thread.CurrentThread.Name + "1");
TaskTest();
Console.WriteLine(Thread.CurrentThread.Name + "2");
Console.ReadLine();
}
private async static void TaskTest()
{
Console.WriteLine(Thread.CurrentThread.Name + "3");
await Task.Delay(2000);
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "FirstTask";
Console.WriteLine(Thread.CurrentThread.Name + "4");
await Task.Delay(2000);
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "SecondTask";
Console.WriteLine(Thread.CurrentThread.Name + "5");
}
If you run this program you will see that await will use different thread. Output:
Main1
Main3
Main2
FirstTask4 // 2 seconds delay
SecondTask5 // 4 seconds delay
But if we remove both await keywords, you will learn that async alone doesn't do much. Output:
Main1
Main3
Main4
Main5
Main2