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 ("starting from the main thread ");

// IsBackground = true, set it to the background thread

Thread t = new Thread (Run) {IsBackground = true };

T. Start ();

Console. WriteLine ("the main thread is doing other things! ");

// When the main thread ends, the background thread ends automatically, whether or not the execution is completed

// Thread. Sleep (300 );

Thread. Sleep (1500 );

Console. WriteLine ("main thread ended ");

}

Static void Run ()

{

Thread. Sleep (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 we will give a simple example of the use of SemaphoreSlim class:

 

Static SemaphoreSlim semLim = new SemaphoreSlim (3); // 3 indicates that only 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 (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 (1500); Console. WriteLine ("task start ");});

Task task = Task. Run () => {

Thread. Sleep (1500 );

Console. WriteLine ("task startup ");

});

Thread. Sleep (300 );

Task. Wait ();

Console. WriteLine ("main thread ended ");

 

The execution result is as follows:

 

 

How to start a new Task: Task. run () or Task. factory. startNew (), which enables the background thread to Wait for the background 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) called by Task );

}

 

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 ("starting from the main thread ");

// The return value type is string.

Task <string> task = Task <string>. Run () => {

Thread. Sleep (2000 );

Return Thread. CurrentThread. ManagedThreadId. ToString ();

});

// The output will not be completed until the task is executed;

Console. WriteLine (task. Result );

Console. WriteLine ("main thread ended ");

 

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 startup -------");

Task <int> task = GetStrLengthAsync ();

Console. WriteLine ("main thread continues execution ");

Console. WriteLine ("value returned by a Task" + task. Result );

Console. WriteLine ("------- the main thread ends -------");

}

Static async Task <int> GetStrLengthAsync ()

{

Console. WriteLine ("GetStrLengthAsync method execution ");

// The string type in <string> returned here, instead of the Task <string>

String str = await GetString ();

Console. WriteLine ("the execution of the GetStrLengthAsync method ends ");

Return str. Length;

}

Static Task <string> GetString ()

{

// Console. WriteLine ("GetString method execution ")

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. Let's look at 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 started --------------------");

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 completes execution.

Result. AsyncWaitHandle. WaitOne ();

Console. WriteLine ("the main program is doing something !!! ");

// Obtain the asynchronous execution result

String returnValue = caller. EndInvoke (out threadId, result );

// Release resources

Result. AsyncWaitHandle. Close ();

Console. WriteLine ("the main program ends --------------------");

Console. Read ();

}

}

Public class AsyncDemo

{

// Method for background thread execution

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 in the thread pool

Parallel. 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 ("starting from the main thread ");

Task <string> task = Task <string>. Run () => {

Thread. Sleep (2000 );

Return Thread. CurrentThread. ManagedThreadId. ToString ();

});

// It will be executed after the task is executed

Task. 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 ("starting from the main thread ");

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.