I have the following code where the continuation code isn't getting executed.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Konsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main starting...");
Task.Run(async () =>
{
await Job1();
})
.ContinueWith(async t =>
{
await Job2();
}).Wait();
Console.WriteLine("Main ending...");
}
public static async Task Job1()
{
await Task.Run(() =>
{
for (int i = 1; i <= 2; i++)
{
Thread.Sleep(1000);
Console.WriteLine($"Job1 {i}");
}
});
}
public static async Task Job2()
{
await Task.Run(() =>
{
for (int i = 1; i <= 2; i++)
{
Thread.Sleep(1000);
Console.WriteLine($"Job2 {i}");
}
});
}
}
}
Console output:
Main starting...
Job1 1
Job1 2
Main ending...
I expected Job2 to be executed as well before the application closed.
To answer you question, you need to 'Unwrap' the task from the first async call as follows:
Task.Run(async () =>
{
await Job1();
})
.ContinueWith(async t =>
{
await Job2();
})
.Unwrap()
.Wait();
Unwrap Documentation
There are a number of other things to comment on here though.
If you are using async/await, you should really use it all the way through. Your question doesn't specify which version of c# you are using. If you are using C# 7.1 or above, you should make your main method an async method as follows:
public static async Task Main()
{
Console.WriteLine("Main starting...");
await Job1();
await Job2();
Console.WriteLine("Main ending...");
}
Also, as pointed out by #Sean, Thread.Sleep is a bad idea in these scenarios, you should use await Task.Delay(1000); instead.
Task.Delay Documentation
A great article with some async/await best practices can be found on MSDN as well.
You should not use ContinueWith; it's a dangerous, low-level method. In this case, you're encountering a problem because ContinueWith does not understand asynchronous delegates.
Ideally, you should replace all calls to ContinueWith (and Wait) with await:
static async Task Main(string[] args)
{
Console.WriteLine("Main starting...");
await Task.Run(async () =>
{
await Job1();
});
await Job2();
Console.WriteLine("Main ending...");
}
If you break out the variables so you can see the types, it will become more clear why the original code wasn't working:
static async Task Main(string[] args)
{
Console.WriteLine("Main starting...");
Task runTask = Task.Run(async () =>
{
await Job1();
});
Task<Task> continuationTask = runTask.ContinueWith(async t =>
{
await Job2();
});
// continuationTask is a Task<Task>.
// This waits for the "outer" task only, not the "inner" task.
continuationTask.Wait();
Console.WriteLine("Main ending...");
}
Related
I simple do not know how to make the following code work, it is suppose to keep running forever inside an infinite loop, and in fact it will work when I remove await Task.Delay from the method Method_FOO, but I need Method_FOO to be async.
I think to make this work the Thread.Start() method needs to be "waitable" (not just the code it runs), but Thread.Start is void. I notice that if I block the execution with eg.: Console.ReadLine it will print the Worked string, but this is not a solution, and is terrible in real life.
This code is just an example, but the threads need to run inside an infinite loop (it is not something I can change), and I need async methods because I need to consume some websockets, and looks like there is no sync client websocket class in C#.
But still, there must be a simple/decent solution for this problem.
public static class Program
{
public static async Task Main(string[] args)
{
var cancellationTokenSource = new CancellationTokenSource();
var thread1 = new Thread(async () => await Run(cancellationTokenSource.Token, "threadName1", Method_FOO));
var thread2 = new Thread(async () => await Run(cancellationTokenSource.Token, "threadName2", Method_FOO));
thread1.Start();
thread2.Start();
}
private static async Task Method_FOO(CancellationToken cancellationToken)
{
Console.WriteLine("It is called...");
await Task.Delay(300, cancellationToken);
//never reach this part
Console.WriteLine("Worked ...");
}
// workd but it is not async
//private static Task Method_FOO(CancellationToken cancellationToken)
//{
// Console.WriteLine("It is called...");
// Console.WriteLine("Worked ...");
// return Task.CompletedTask;
//}
private static async Task Run(CancellationToken cancellationToken, string threadName, Func<CancellationToken, Task> function)
{
try
{
while (true)
{
await function(cancellationToken);
Console.WriteLine($"{threadName} waiting ...");
cancellationToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1));
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
At this point in history, new Thread is pretty much only useful for COM interop. In every other scenario, there are better solutions. In this case, you can send work to the thread pool by using Task.Run:
public static async Task Main(string[] args)
{
var cancellationTokenSource = new CancellationTokenSource();
var task1 = Task.Run(async () => await Run(cancellationTokenSource.Token, "threadName1", Method_FOO));
var task2 = Task.Run(async () => await Run(cancellationTokenSource.Token, "threadName2", Method_FOO));
await Task.WhenAll(task1, task2);
}
Thread don't wait task's end. When the 3 threads (main, thread1, thread2), the program is closed and running task killed.
You can make the method Run synchronous and manualy wait the task end, like :
public static class Program
{
public static async Task Main(string[] args)
{
var cancellationTokenSource = new CancellationTokenSource();
var thread1 = new Thread(() => Run(cancellationTokenSource.Token, "threadName1", Method_FOO));
var thread2 = new Thread(() => Run(cancellationTokenSource.Token, "threadName2", Method_FOO));
thread1.Start();
thread2.Start();
}
private static async Task Method_FOO(CancellationToken cancellationToken)
{
Console.WriteLine("It is called...");
await Task.Delay(300, cancellationToken);
Console.WriteLine("Worked ...");
}
private static void Run(CancellationToken cancellationToken, string threadName, Func<CancellationToken, Task> function)
{
try
{
while (true)
{
function(cancellationToken).Wait();
Console.WriteLine($"{threadName} waiting ...");
cancellationToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1));
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
Edit : Why not directly use the tasks?
public static void Main(string[] args)
{
var cancellationTokenSource = new CancellationTokenSource();
var task1 = Run(cancellationTokenSource.Token, "threadName1", Method_FOO);
var task2 = Run(cancellationTokenSource.Token, "threadName2", Method_FOO);
Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith(t => cancellationTokenSource.Cancel());
Task.WaitAll(task1, task2);
}
In a console application I've created a List of Task in which im adding three async tasks:
static void Main(string[] args)
{
List<Task> task_list= new List<Task>();
Task task_1=new Task(async () => await Task_method1());
Task task_2=new Task(async () => await Task_method2());
Task task_3=new Task(async () => await Task_method3());
task_list.Add(task_1);
task_list.Add(task_2);
task_list.Add(task_3);
Task.WaitAll(task_list.ToArray());
foreach (Task t in task_list)
{
Console.WriteLine("Task {0} Status: {1}", t.Id, t.Status);
}
Console.ReadKey();
}
And here's the method definition of 3 Task:
public async Task<HttpResponseMessage> Task_Method1()
{
//Code for Response
return Response;
}
public async Task<HttpResponseMessage> Task_Method2()
{
//Code for Response
return Response;
}
public async Task<HttpResponseMessage> Task_Method3()
{
//Code for Response
return Response;
}
Problem is that they are running parallely, and there's no serialized order of tasks. I searched a lot but get didn't get an appropriate solution for running them in series.
For reference see the image below:
RUN1:
RUN2:
RUN3:
You must have omitted some code, as even if the tasks complete in arbitrary order, your List's order should remain unchanged, yet you show your output with the List's order changing.
Then re actually doing it, perhaps I'm missing something, but if you want them to run in order why not just do:
static void Main(string[] args)
{
MainAsync().Wait();
}
private async Task MainAsync()
{
var response1 = await Task_method1();
var response2 = await Task_method2();
var response3 = await Task_method3();
// Write results, etc.
Console.ReadKey();
}
Here's some code I'm working with, that fires of three tasks. My Stop is called, and from the output, it looks as though the tasks finish after Stop returns, which isn't what I'd expect.
This is Visual Studio 2013 with .NET 4.5.1
I tried the same using AutoResetEvent which worked as expected.
Here's the output from this:
Three tasks without auto reset
Starting...
FIRST
SECOND
THIRD
Running...
FIRST
FIRST
FIRST
SECOND
FIRST
FIRST
THIRD
...
SECOND
FIRST
Stopping...
THIRD
All done!
First done
Second done
Third done
What I'd expect to see is:
First done
Second done
Third done
All done!
Here's the code (I even added locking around the Console output, but it made no difference):
public class ThreeTasksWithoutAutoResetEvent
{
private CancellationTokenSource cancellation;
private Task[] tasks;
private object obj = new object();
public ThreeTasksWithoutAutoResetEvent()
{
Console.WriteLine("Three tasks without auto reset");
cancellation = new CancellationTokenSource();
tasks = new Task[3];
Message("Starting...");
Start();
Message("Running...");
Thread.Sleep(3000);
Message("Stopping...");
Stop();
Message("All done!");
}
private void Start()
{
tasks[0] = this.First(cancellation.Token);
tasks[1] = this.Second(cancellation.Token);
tasks[2] = this.Third(cancellation.Token);
}
private async void Stop()
{
cancellation.Cancel();
await Task.WhenAll(tasks);
}
private async Task First(CancellationToken token)
{
await Task.Run(
() =>
{
while (!token.IsCancellationRequested)
{
Message("FIRST");
Thread.Sleep(100);
}
Message("First done");
}, token);
}
private async Task Second(CancellationToken token)
{
await Task.Run(
() =>
{
while (!token.IsCancellationRequested)
{
Message("SECOND");
Thread.Sleep(300);
}
Message("Second done");
}, token);
}
private async Task Third(CancellationToken token)
{
await Task.Run(
() =>
{
while (!token.IsCancellationRequested)
{
Message("THIRD");
Thread.Sleep(500);
}
Message("Third done");
}, token);
}
private void Message(string message)
{
lock (obj)
{
Console.WriteLine(message);
}
}
}
Because you're not waiting for Stop method to finish. You can't wait for an async void method. You need return a Task, so that the caller can wait/await for it to complete.
private Task Stop()
{
cancellation.Cancel();
return Task.WhenAll(tasks);
}
Then you can call Stop().Wait(); instead of Stop. That will wait for WhenAll to complete.
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
I wonder how to accomplish the same thing the below program does without using extra threads or await and async keywords but only Tasks. A sample code would be awesome. It seems to me that we need to use TaskCompletionSource and Async versions of the IO-bound operations or any long-running operations.
static void Main(string[] args)
{
Task t = Go();
Console.WriteLine("Hello World");
Task.Delay(1000).GetAwaiter().OnCompleted(() => { Console.WriteLine("Completed"); });
Console.ReadLine();
}
static async Task Go()
{
var task = PrintAnswerToLife();
await task;
Console.WriteLine("Done");
}
static async Task PrintAnswerToLife()
{
var task = GetAnswerToLife();
int answer = await task;
Console.WriteLine(answer);
}
static async Task<int> GetAnswerToLife()
{
var task = Task.Delay(2000);
await task;
int answer = 21 * 2;
return answer;
}
You can do a pretty straightforward translation of async / await into Task by using ContinueWith. Other translations are also possible, e.g., Task.Delay becomes System.Threading.Timer.
The basic pattern is, for any async method that does an await:
static async Task Go()
{
var task = PrintAnswerToLife();
await task;
Console.WriteLine("Done");
}
becomes:
static Task Go()
{
var tcs = new TaskCompletionSource<object>();
var task = PrintAnswerToLife();
task.ContinueWith(_ =>
{
Console.WriteLine("Done");
tcs.SetResult(null);
});
return tcs.Task;
}
Correct error handling is a lot more work.