In C #, what are Thread, Task, Async/Await, and IAsyncResult !,

Source: Internet
Author: User

In C #, what are Thread, Task, Async/Await, and IAsyncResult !,

Speaking of Asynchronization, Thread, Task, async/await, and IAsyncResult, these things cannot be bypassed. Today I will talk about them one by one.

1. Thread)

Multithreading means that multiple execution parts in an application can be executed simultaneously. for time-consuming operations (such as io and database operations), or waiting for response (such as WCF Communication) you can enable the background thread to execute it separately, so that the main thread will not be blocked and you can continue to execute it. Wait until the background thread completes execution, notify the main thread, and then perform the corresponding operation!

It is relatively simple to start a new thread in C #.

Static void Main (string [] args) {Console. writeLine ("main Thread start"); // IsBackground = true, set it to the background Thread t = new Thread (Run) {IsBackground = true}; t. start ();
Console. WriteLine ("the main thread is doing other things! "); // The main Thread ends, and the background Thread ends automatically, no matter whether the execution is completed or not. // Thread. sleep (1, 300); Thread. sleep (1, 1500); Console. writeLine ("main Thread ended");} static void Run () {Thread. sleep (1, 700); Console. writeLine ("this is a background thread call ");}

The execution result is as follows,

It can be seen that after the background thread is started, the main thread continues to execute and does not wait until the background thread finishes executing.

1.1 Thread Pool

Imagine if a large number of tasks need to be processed, such as processing HTTP requests in the website background, is it necessary to create a background thread for each request? Obviously not suitable. This will occupy a large amount of memory and the frequent creation process will seriously affect the speed. What should we do? To solve this problem, the thread pool stores the created threads to form a thread pool (which contains multiple threads). when processing a task, if there are Idle threads in the thread pool (after the previous task is executed, the thread will not be recycled and will be set to idle ), directly call the thread execution in the thread pool (for example, the Application object in the asp.net processing mechanism ),

Example:

for (int i = 0; i < 10; i++){    ThreadPool.QueueUserWorkItem(m =>    {        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());    });}Console.Read();

Running result:

As you can see, 10 threads are not created even though 10 times are executed.

1.2 semaphores (Semaphore)

Semaphore coordinates threads and limits the number of threads used to access a certain resource.

Here is a simple example of the use of the SemaphoreSlim class:

Static SemaphoreSlim semLim = new SemaphoreSlim (3); // 3 indicates that up to three threads can simultaneously access static void Main (string [] args) {for (int I = 0; I <10; I ++) {new Thread (SemaphoreTest ). start ();} Console. read ();} static void SemaphoreTest () {semLim. wait (); Console. writeLine ("Thread" + Thread. currentThread. managedThreadId. toString () + "start execution"); Thread. sleep (1, 2000); Console. writeLine ("Thread" + Thread. currentThread. managedThreadId. toString () + "execution completed"); semLim. release ();}

The execution result is as follows:

We can see that at the beginning, only three threads are being executed. After a thread is executed and released, a new thread will be executed!

In addition to the SemaphoreSlim class, you can also use the Semaphore class. It feels more flexible. If you are interested, you can search for it. We will not describe it here!

2. Task

The Task is added by. NET4.0. Similar to the ThreadPool function of the Thread pool, when a Task is used to start a new Task, the Thread is called from the Thread pool, and a new Thread is created every time the Thread is instantiated.

Console. writeLine ("main thread startup"); // Task. run starts a thread // The Task starts a background thread. To Wait for the background thread to complete execution in the main thread, you can call the Wait method // Task task = Task. factory. startNew () => {Thread. sleep (1, 1500); Console. writeLine ("task start") ;}); Task task = Task. run () => {Thread. sleep (1, 1500); Console. writeLine ("task startup") ;}); Thread. sleep (300); task. wait (); Console. writeLine ("the main thread ends ");

The execution result is as follows:

How to enable a new Task: Task. Run () or Task. Factory. StartNew (). The background thread is enabled.

To Wait for the backend thread to complete execution in the main thread, you can use the Wait method (it will be executed in synchronous mode ). If you do not use Wait, it will be executed asynchronously.

Compare Task and Thread:

Static void Main (string [] args) {for (int I = 0; I <5; I ++) {new Thread (Run1 ). start () ;}for (int I = 0; I <5; I ++) {Task. run () =>{ Run2 () ;}}} static void Run1 () {Console. writeLine ("Thread Id =" + Thread. currentThread. managedThreadId);} static void Run2 () {Console. writeLine ("Thread Id =" + Thread. currentThread. managedThreadId );}

Execution result:

As you can see, using the Thread directly will enable five threads, and using the Task (using the Thread pool) to enable three!

2.1 Task <TResult>

Task <TResult> is the Task with returned values, and TResult is the return value type.

Console. writeLine ("main thread start"); // the return value type is stringTask <string> task = Task <string>. run () => {Thread. sleep (2000); return Thread. currentThread. managedThreadId. toString () ;}); // it will not be output until the task is executed; Console. writeLine (task. result); Console. writeLine ("the main thread ends ");

Running result:

The return value can be obtained through task. Result. If the value is not completed by the background thread, it will wait for execution to complete!

To put it simply:

Task tasks can be canceled by using the CancellationTokenSource class. It is easy to use and can be searched if you are interested!

3. async/await

Async/await is introduced in C #5.0. The usage is as follows:

Static void Main (string [] args) {Console. writeLine ("------- main thread start -------"); Task <int> task = GetStrLengthAsync (); Console. writeLine ("main thread continues executing"); Console. writeLine ("value returned by a Task" + task. result); Console. writeLine ("------- main thread ends -------");} static async Task <int> GetStrLengthAsync () {Console. writeLine ("GetStrLengthAsync method starts execution"); // The string type returned here in <string>, instead of Task <string> string str = await GetString (); Console. writeLine ("GetStrLengthAsync method execution ends"); return str. length;} static Task <string> GetString (){
// Console. writeLine ("GetString method to start executing") return Task <string>. run () => {Thread. sleep (2000); return "GetString return value ";});}

Async is used to modify the method, indicating that this method is asynchronous. The declared method must return the following types: void, Task, or Task <TResult>.

Await must be used to modify the Task or Task <TResult>, and can only appear in asynchronous methods that have been modified with the async keyword. Generally, async/await is meaningful to appear in pairs,

Check the running result:

As you can see, after the main function calls the GetStrLengthAsync method, It will be executed synchronously before await. The main function will not return to continue execution until the await keyword is encountered.

Is the program automatically enabling a background thread to execute the GetString method when the await keyword is encountered?

Add the line comment in the GetString method. The running result is:

As you can see, after encountering the await keyword, the operation after the GetStrLengthAsync method is not continued, nor is it immediately returned to the main function, but the first line of GetString is executed, in this way, we can judge that await has not enabled a new thread to execute the GetString method. Instead, the GetString method is executed synchronously until the Task is executed in the GetString method <string>. the background thread is enabled only when Run () is Run!

So what is the role of await?

It can be understood literally. The task mentioned above. wait allows the main thread to wait for the background thread to complete the execution. await is similar to wait. It is also waiting for the Task <string>. the background thread starting from Run () is executed completely. The difference is that await does not block the main thread and only suspends the execution of the GetStrLengthAsync method.

So how does await achieve this? Have you enabled a new thread to wait?

There are only two threads (main thread and Task enabled thread )! As for how to do this (I do not know...> _ <), study it if you are interested!

4. IAsyncResult

IAsyncResult is available since. NET1.1. classes that contain asynchronous methods need to implement it, and the Task class implements this interface.

How can I implement Asynchronization without the help of tasks?

Class Program {static void Main (string [] args) {Console. writeLine ("main program starts ------------------"); int threadId; AsyncDemo ad = new AsyncDemo (); AsyncMethodCaller caller = new AsyncMethodCaller (ad. testMethod); IAsyncResult result = caller. begininvoke( 3000, out threadId, null, null); Thread. sleep (0); Console. writeLine ("main thread {0} is running. ", Thread. currentThread. managedThreadId) // The thread will be blocked until the background thread finishes executing r Esult. AsyncWaitHandle. WaitOne (); Console. WriteLine ("the main program is doing something !!! "); // Obtain the asynchronous execution result string returnValue = caller. endInvoke (out threadId, result); // release the resource result. asyncWaitHandle. close (); Console. writeLine ("main program ended ------------------"); Console. read () ;}} public class AsyncDemo {// public string TestMethod (int callDuration, out int threadId) {Console. writeLine ("test method execution started. "); Thread. sleep (callDuration); threadId = Thread. currentThread. managedThreadId; return String. format ("test method execution time {0 }. ", callDuration. toString () ;}} public delegate string AsyncMethodCaller (int callDuration, out int threadId );

The key step is the red part. The running result is as follows:

The usage of tasks is not very different! Result. AsyncWaitHandle. WaitOne () is similar to the Wait of a Task.

5. Parallel

Finally, let's look at the simple method to enable multithreading in a loop:

Stopwatch wattings = new Stopwatch (); watch1.Start (); for (int I = 1; I <= 10; I ++) {Console. write (I + ","); Thread. sleep (1000);} watch1.Stop (); Console. writeLine (watch1.Elapsed); Stopwatch watch2 = new Stopwatch (); watch2.Start (); // calls the thread Parallel in the thread pool. for (1, 11, I => {Console. writeLine (I + ", Thread ID:" + Thread. currentThread. managedThreadId); Thread. sleep (1000) ;}); watch2.Stop (); Console. writeLine (watch2.Elapsed );

Running result:

Cyclic List <T>:

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 6, 7, 8, 9 };
Parallel.ForEach<int>(list, n =>{ Console.WriteLine(n); Thread.Sleep(1000);});

Execute the methods in the Action [] array:

Action [] actions = new Action [] {new Action () => {Console. writeLine ("method 1");}), new Action () => {Console. writeLine ("method 2") ;}}; Parallel. invoke (actions );
6. asynchronous callback

For simplicity (lazy), the returned values of all the tasks in this article are obtained directly using Task. result. If the background tasks are not completed, the main thread will wait for them to complete. In this way, it is the same as synchronization, which is generally not used in this way. A simple demonstration of the use of the Task callback function:

Console. writeLine ("main thread start"); Task <string> task = Task <string>. run () => {Thread. sleep (2000); return Thread. currentThread. managedThreadId. toString () ;}); // the task will be executed after the task is executed. getAwaiter (). onCompleted () => {Console. writeLine (task. result) ;}); Console. writeLine ("main thread ended"); Console. read ();

Execution result:

The code in OnCompleted will be executed after the task is completed!

In addition, task. ContinueWith () is also an important method:

Console. writeLine ("main thread start"); Task <string> task = Task <string>. run () => {Thread. sleep (2000); return Thread. currentThread. managedThreadId. toString () ;}); task. getAwaiter (). onCompleted () => {Console. writeLine (task. result) ;}); task. continueWith (m => {Console. writeLine ("the first task is over! I am the second task ") ;}); Console. WriteLine (" main thread ended "); Console. Read ();

Execution result:

The ContinueWith () method allows the background thread to continue executing new tasks.

The use of tasks is quite flexible. You can study it. Well, all the above content is available. The length and capabilities are limited. I hope it will be useful to you!

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.