I've created a little demo project to help me understand how I can use Cancellation Tokens. I understand that you cancel a token and check if a cancellation has been requested, but is there a way that I can check whether the cancellation has been realised? In my example below, I don't want to run Work() again until DoWork() has finished running.
public class Program
{
public static CancellationTokenSource tokenSource;
private static void Main(string[] args)
{
while (true)
{
Work();
}
}
public static async void Work()
{
tokenSource = new CancellationTokenSource();
Console.WriteLine("Press any key to START doing work");
Console.ReadLine();
Console.WriteLine("Press any key to STOP doing work");
DoWork(tokenSource.Token);
Console.ReadLine();
Console.WriteLine("Stopping...");
tokenSource.Cancel();
}
public static async void DoWork(CancellationToken cancelToken)
{
while (true)
{
Console.WriteLine("Working...");
await Task.Run(() =>
{
Thread.Sleep(1500);
});
if (cancelToken.IsCancellationRequested)
{
Console.WriteLine("Work Cancelled!");
return;
}
}
}
}
You typically don't want to make your DoWork function async void -- make it async Task instead. That way you can see when it's completed (or been cancelled).
You also probably want to use cancelToken.ThrowIfCancellationRequested(). This throws an OperationCanceledException, which you can catch.
public class Program
{
public static CancellationTokenSource tokenSource;
private static async Task Main(string[] args)
{
while (true)
{
await Work();
}
}
public static async Task Work()
{
tokenSource = new CancellationTokenSource();
Console.WriteLine("Press any key to START doing work");
Console.ReadLine();
Console.WriteLine("Press any key to STOP doing work");
var task = DoWork(tokenSource.Token);
Console.ReadLine();
Console.WriteLine("Stopping...");
tokenSource.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
// Task was cancelled
}
}
public static async Task DoWork(CancellationToken cancelToken)
{
while (true)
{
Console.WriteLine("Working...");
await Task.Run(() =>
{
Thread.Sleep(1500);
});
cancelToken.ThrowIfCancellationRequested();
}
}
}
This code relies on "async main", which was introduced in C# 7. If you don't have this, you can write your Main method as:
private static void Main(string[] args)
{
while (true)
{
Work().Wait();
}
}
You will make the most out of a CancellationToken if all your operations are asynchronous and cancellable. This way cancelling the token will have immediate effect. You won't have to wait for a Thread.Sleep or other blocking call to complete.
public static async Task DoWork(CancellationToken cancellationToken)
{
while (true)
{
await Console.Out.WriteLineAsync("Working...");
await Task.Delay(1500, cancellationToken);
}
}
In this example the token is passed only to Task.Delay, because the WriteLineAsync is not cancellable on .NET Framework (it is on .NET Core).
An OperationCanceledException will be raised by Task.Delay when the token is cancelled.
I am learning about async/await and created a dummy console application. When I try to get the result from async method the program just hangs. Any idea what is wrong in the following code.
static void Main(string[] args)
{
var task = Task.Factory.StartNew(() => 5);
var x = TestAsync();
//x.Start();
Console.WriteLine(x.Result);
}
private static Task<int> CalculateValue()
{
Console.WriteLine("In CalculateValue"); // This line is printed.
Task<int> t = new Task<int>(GetValue); // The program hangs here.
return t;
}
public static async Task<int> TestAsync()
{
int result = await CalculateValue();
return result;
}
private static int GetValue()
{
return 10;
}
First of all:
Task<int> t = new Task<int>(GetValue); // The program hangs here.
is incorrect, the program actually hangs here :
Console.WriteLine(x.Result);
.Result blocks current thread until task x completes execution and returns result. It never completes as it awaits task returned by CalculateValue method whis is this task:
Task<int> t = new Task<int>(GetValue);
This is so called 'cold Task' which means that it's a task in an inactive state.
To start a 'hot' task (which basically means start the task) use the Task.Run method:
Task<int> t = Task.Run(GetValue);
I'm totally green with TPL and want to execute an async method in a console application.
My code:
static void Main()
{
Task<string> t = MainAsync();
t.Wait();
Console.ReadLine();
}
static async Task<string> MainAsync()
{
var result = await (new Task<string>(() => { return "Test"; }));
return result;
}
This task runs forever. Why? What am I missing?
You don't start your task. This is why Wait doesn't return. Try
var result = await Task.Run<string>(() => { return "Test"; });
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.