TaskAwaiter
Let me talk firstTaskAwaiter
,TaskAwaiter
Denotes an object waiting for the asynchronous task to complete and provides parameters for the result.
Task has aGetAwaiter()
Method will returnTaskAwaiter
orTaskAwaiter<TResult>
,TaskAwaiter
Type isDefined in the namespace.
TaskAwaiter
The properties and methods of types are as follows:
property:
property | illustrate |
---|---|
IsCompleted | Gets a value indicating whether the asynchronous task has been completed. |
method:
method | illustrate |
---|---|
GetResult() | End the waiting for the asynchronous task to complete. |
OnCompleted(Action) | Set the operation to execute when the TaskAwaiter object stops waiting for the asynchronous task to complete. |
UnsafeOnCompleted(Action) | Plan the continuation of asynchronous tasks related to this awaiter. |
Examples of use are as follows:
static void Main() { Task<int> task = new Task<int>(()=> { ("I'm a front-drive mission"); ((1)); return 666; }); TaskAwaiter<int> awaiter = (); (()=> { ("When the predecessor task is completed, I will continue to execute it"); }); (); (); }
In addition, we mentioned earlier that an unhandled exception occurs in a task and the task is terminated, which is also considered completing the task.
Another way to continue
We introduced it in the previous section.ContinueWith()
Methods to achieve continuation, here we introduce another continuation method.ConfigureAwait()
。
.ConfigureAwait()
If you want to try to marshall the continuation task back to the original context, thentrue
; otherwisefalse
。
Let me explain,.ContinueWith()
Continued tasks. After the current drive task is completed, the continued tasks will continue to be executed on this thread. This method is synchronous, with the former and the latter running continuously on one thread.
.ConfigureAwait(false)
The method can be asynchronous. After the predecessor method is completed, the subsequent tasks can be ignored, and the subsequent tasks can be run on any thread. This feature is especially useful in UI interface programs.
You can refer to:/bynder-tech/c-why-you-should-use-configureawait-false-in-your-library-code-d7837dce3d7f
Its usage is as follows:
static void Main() { Task<int> task = new Task<int>(()=> { ("I'm a front-drive mission"); ((1)); return 666; }); ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter awaiter = (false).GetAwaiter(); (()=> { ("When the predecessor task is completed, I will continue to execute it"); }); (); (); }
ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter
Have andTaskAwaiter
Same attributes and methods.
.ContinueWith()
and.ConfigureAwait(false)
Another difference is that the former can continue multiple tasks and tasks that continue tasks (multiple layers). The latter can only continue one layer of tasks (one layer can have multiple tasks).
Another way to create tasks
As mentioned earlier, there are three ways to create tasks:new Task()
、()
、()
, Let’s learn the fourth method now:TaskCompletionSource<TResult>
type.
Let's take a lookTaskCompletionSource<TResulr>
Properties and methods of types:
property:
property | illustrate |
---|---|
Task | Gets the TaskCompletionSource created by this Task. |
method:
method | illustrate |
---|---|
SetCanceled() | Convert the underlying Task to Canceled state. |
SetException(Exception) | Converts the underlying Task to a Faulted state and binds it to a specified exception. |
SetException(IEnumerable) | Convert the underlying Task to Faulted state and bind some exception objects to it. |
SetResult(TResult) | Converts the underlying Task to RanToCompletion state. |
TrySetCanceled() | Try to convert the underlying Task to a Canceled state. |
TrySetCanceled(CancellationToken) | Try to convert the underlying Task to Canceled state and enable the cancel tag to be stored in the canceled task. |
TrySetException(Exception) | Try to convert the underlying Task to a Faulted state and bind it to a specified exception. |
TrySetException(IEnumerable) | Try to convert the underlying Task to Faulted state and bind some exception objects to it. |
TrySetResult(TResult) | Try to convert the underlying Task to RanToCompletion state. |
TaskCompletionSource<TResulr>
Classes can control the life cycle of tasks.
First, pass.Task
Attribute, get oneTask
orTask<TResult>
。
TaskCompletionSource<int> task = new TaskCompletionSource<int>(); Task<int> myTask = ; // Task myTask = ;
Then pass()
Method to controlmyTask
Life cycle, but myTask itself has no task content.
Examples of use are as follows:
static void Main() { TaskCompletionSource<int> task = new TaskCompletionSource<int>(); Task<int> myTask = ; // task control myTask // Open a new task to do experiments Task mainTask = new Task(() => { ("I can control myTask tasks"); ("Press any key and I let the myTask task complete immediately"); (); (666); }); (); ("Start wait for myTask to return result"); (); ("Finish"); (); }
Others, for exampleSetException(Exception)
The methods can be explored by yourself, so I won’t go into details here.
References:/premier-developer/the-danger-of-taskcompletionsourcet-class/
This article is well explained, and there are pictures:/gigilabs/taskcompletionsource-by-example/
Implement a type that supports synchronous and asynchronous tasks
This part of the content is correctTaskCompletionSource<TResult>
Continue to explain.
Here we design a class similar to Task type that supports synchronous and asynchronous tasks.
- Users can use
GetResult()
Synchronously obtain results; - Users can use
RunAsync()
Execute tasks, use.Result
Attributes get the result asynchronously;
It is implemented as follows:
/// <summary> /// Implement the types of synchronous tasks and asynchronous tasks/// </summary> /// <typeparam name="TResult"></typeparam> public class MyTaskClass<TResult> { private readonly TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>(); private Task<TResult> task; // Save the tasks that the user needs to perform private Func<TResult> _func; // Whether the execution has been completed, synchronous or asynchronous execution is OK private bool isCompleted = false; // Task execution results private TResult _result; /// <summary> /// Get the execution result /// </summary> public TResult Result { get { if (isCompleted) return _result; else return ; } } public MyTaskClass(Func<TResult> func) { _func = func; task = ; } /// <summary> /// Synchronize method to get results /// </summary> /// <returns></returns> public TResult GetResult() { _result = _func.Invoke(); isCompleted = true; return _result; } /// <summary> /// Execute tasks asynchronously /// </summary> public void RunAsync() { (() => { (_func.Invoke()); isCompleted = true; }); } }
In the Main method, we create a task example:
class Program { static void Main() { // Instantiate the task class MyTaskClass<string> myTask1 = new MyTaskClass<string>(() => { ((1)); return ""; }); // Get results directly synchronously (()); // Instantiate the task class MyTaskClass<string> myTask2 = new MyTaskClass<string>(() => { ((1)); return ""; }); // Get the results asynchronously (); (); (); } }
()
Microsoft Documentation Explanation: Create a Task, which is completed by the cancel operation performed by the specified cancel tag.
Here I copied oneExample:
var token = new CancellationToken(true); Task task = (token); Task<int> genericTask = <int>(token);
There are many such examples on the Internet, but what exactly is this thing used for? Just new?
Let's explore with questions, let's take an example:
public static Task Test() { CancellationTokenSource source = new CancellationTokenSource(); (); return <object>(); } static void Main() { var t = Test(); // Set breakpoints here to monitor variables (); }
()
A cancelled task can be constructed. I've been searching for a long time and haven't found a good example. If a task is cancelled before it starts, then use()
It's very good.
Here are many examples to refer to:/csharp-examples/()/
How to cancel a task internally
We have discussed before, usingCancellationToken
Cancel the token pass parameters and cancel the task. But they are all delivered from the outside, so there is no need to implement it here.CancellationToken
You can cancel the task.
We can useCancellationToken
ofThrowIfCancellationRequested()
Method throwException, then terminate the task, and the task will become canceled, but the task needs to pass in a token first.
Here I will design a more difficult thing, a class that can execute multiple tasks in order.
Examples are as follows:
/// <summary> /// Asynchronous type that can complete multiple tasks /// </summary> public class MyTaskClass { private List<Action> _actions = new List<Action>(); private CancellationTokenSource _source = new CancellationTokenSource(); private CancellationTokenSource _sourceBak = new CancellationTokenSource(); private Task _task; /// <summary> /// Add a task /// </summary> /// <param name="action"></param> public void AddTask(Action action) { _actions.Add(action); } /// <summary> /// Start executing tasks /// </summary> /// <returns></returns> public Task StartAsync() { // _ = new Task() is invalid for this example _task = (() => { for (int i = 0; i < _actions.Count; i++) { int tmp = i; ($"The {tmp} A task"); if (_source.) { = ; ("The mission has been cancelled"); = ; _sourceBak.Cancel(); _sourceBak.(); } _actions[tmp].Invoke(); } },_sourceBak.Token); return _task; } /// <summary> /// Cancel the task /// </summary> /// <returns></returns> public Task Cancel() { _source.Cancel(); // You can save it here _task = <object>(_source.Token); return _task; } }
In the Main method:
static void Main() { // Instantiate the task class MyTaskClass myTask = new MyTaskClass(); for (int i = 0; i < 10; i++) { int tmp = i; (() => { ("Task 1 Start"); ((1)); ("Task 1 End"); ((1)); }); } // Equivalent to () Task task = (); ((1)); ($"Whether the task has been canceled:{}"); // Cancel the task = ; ("Press any key to cancel the task"); = ; (); var t = (); // Cancel the task ((2)); ($"Whether the task has been canceled:【{}】"); (); }
You can cancel tasks at any stage.
Yield keywords
Iterator keywords make the data not need to be returned at once, and can iterate one by one when needed, which is also equivalent to asynchronous.
The iterator method runs toyield return
When a statement is made, aexpression
, and retain its current position in the code. The next time the iterator function is called, execution will start again from that location.
Can be usedyield break
Statement to terminate iteration.
Official Documentation:/zh-cn/dotnet/csharp/language-reference/keywords/yield
Most of the examples online areforeach
Yes, some students don’t understand what this means. Let me briefly explain it here.
We can also write an example like this:
There is no more hereforeach
Now.
private static int[] list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; private static IEnumerable<int> ForAsync() { int i = 0; while (i < ) { i++; yield return list[i]; } }
However, the student asked again that the object returned by this return needs to implement thisIEnumerable<T>
Is that OK? What does those documents talk about is iterator interfaces, and what are they?
We can change the example first:
private static int[] list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; private static IEnumerable<int> ForAsync() { int i = 0; while (i < ) { int num = list[i]; i++; yield return num; } }
You call it in the Main method to see if it works normally?
static void Main() { foreach (var item in ForAsync()) { (item); } (); }
This means thatyield return
The returned object does not need to be implementedIEnumerable<int>
method.
actuallyyield
It is a syntactic sugar keyword, you just need to call it in a loop.
static void Main() { foreach (var item in ForAsync()) { (item); } (); } private static IEnumerable<int> ForAsync() { int i = 0; while (i < 100) { i++; yield return i; } } }
It will be automatically generatedIEnumerable<T>
, without you need to implement it firstIEnumerable<T>
。
Supplementary knowledge points
There are many methods for thread synchronization: Critical Section, Mutex, Semaphores, Events, Tasks;
()
and()
Encapsulated Task;()
yes()
simplified form;Some places
net Task()
is invalid; but()
and()
Can;
This is all about this article about the basics of the C# multi-threaded series of tasks (III). I hope it will be helpful to everyone's learning and I hope everyone will support me more.