C #: asynchronous programming and thread usage (. NET 4.5)

Source: Internet
Author: User

C #: asynchronous programming and thread usage (. NET 4.5)

Asynchronous programming and thread processing are important features of concurrent or parallel programming. To implement asynchronous programming, you can use threads or not. Speaking of Asynchronization and thread at the same time will help us better understand their features.

 

This article involves key knowledge points
 

1. asynchronous programming

2. Use of threads

3. Task-Based asynchronous mode

4. Parallel Programming

5. Summary
 

Asynchronous programming
 

What is asynchronous operation? Asynchronous operations refer to operations that can run independently without relying on the main process or other processing processes. Generally, the C # program starts from the Main method and ends when the Main method returns. All operations are performed in sequence. Operations are sequential. An operation can be executed only after the previous operation is completed. Example code:
 

1: static void Main (string [] args)

2:

3 :{

4:

5: DoTaskOne ();

6:

7: DoTaskTwo ();

8:

9 :}

After the "DoTaskOne" method is completed, DoTaskTwo () can be executed.
 

In asynchronous programming, the main call thread is not blocked. After the method running in the background is called, the execution process immediately returns to the called thread and continues to execute other tasks. The background running method is usually implemented by a thread or task.
 

In the preceding example, if "DoTaskOne" is an asynchronous call after the "DoTaskOne" method is successfully called, the execution process is immediately returned to the Main method and the "DoTaskTwo" method is continued.

C # provides the Thread class creation Thread to implement asynchronous programming, or use the asynchronous mode provided by. NET to implement asynchronous programming .. NET provides three different asynchronous modes:
 

1. asynchronous programming model (APM) Mode

2. Event-based asynchronous mode (EAP)

3. Task-Based asynchronous mode (TAP)
 

The first two models are not officially recommended by Microsoft. We will discuss in detail the task-based asynchronous mode (TAP ):
 

Thread usage
 

Asynchronous programming mode is introduced in. NET 4.5. In most cases, we do not need to manually create a thread. The compiler has replaced the developer to do this.
 

Creating a New thread is time consuming. In general, asynchronous and parallel programming uses "Task-Based asynchronous mode (TAP)" and "task parallel Library (TPL. If you need to control the thread function, you need to use other modes.
 

Both TAP and TPL are Task-based. Generally, a task is a thread called from the thread pool (the thread pool is a set of threads created and maintained by the. NET Framework. If we use a task, we do not need to directly call the thread pool.
 

Tasks can run in the following situations:
 

1. In the running thread

2. In the new thread

3. Starting from a thread in the thread pool

4. run without a thread
 

If the task mechanism is used, developers do not have to worry about the creation or use of threads. the. NET Framework has solved this problem for us.
 

To control the thread, perform the following operations:
 

1. Set the thread name

2. Set thread priority

3. Set the thread to run on the frontend or backend
 

We can use the Thread class to create a thread.
 

Use the Thread class to create a Thread
 

The constructor of the Thread class receives parameters of the delegate type.
 

1. ThreadStart: defines a method with null return values without parameters.

2. ParameterizedThreadStart: defines a parameter of the object type with the returned value being null.
 

The following is a simple example to Start a new thread using the Start method:
 

1: static void Main (string [] args)

2:

3 :{

4:

5: Thread thread = new Thread (DoTask );

6:

7: thread. Start (); // Start DoTask method in a new thread

8:

9: // Do other tasks in main thread

10:

11 :}

12:

13: static public void DoTask (){

14:

15: // do something in a new thread

16:

17 :}
 

The Lamda expression can be used to replace the thread Name:
 

1: static void Main (string [] args)

2:

3 :{

4:

5: Thread thread = new Thread () => {

6:

7: // do something in a new thread

8:

9 :});

10:

11: thread. Start (); // Start a new thread

12:

13: // Do other tasks in main thread

14:

15 :}
 

If you do not need to reference variables, you can directly start the thread as follows:
 

1: static void Main (string [] args)

2:

3 :{

4:

5: new Thread () => {

6:

7: // do something in a new thread

8:

9:}). Start (); // Start a new thread

10:

11: // Do other tasks in main thread

12:

13 :}
 

However, if you want to control the thread object and set some attributes for the thread, you must reference the thread variable after the thread is created. Set values for different attributes of the thread object as follows:
 

1: static void Main (string [] args)

2:

3 :{

4:

5: Thread thread = new Thread (DoTask );

6:

7: thread. Name = "My new thread"; // Asigning name to the thread

8:

9: thread. IsBackground = false; // Made the thread forground

10:

11: thread. Priority = ThreadPriority. AboveNormal; // Setting thread priority

12:

13: thread. Start (); // Start DoTask method in a new thread

14:

15: // Do other task in main thread

16:

17 :}
 

Call the referenced variable to execute some operations, such as suspending the thread or waiting for the blocked thread by calling the join method.
 

If you want to pass the value through the function, you can pass the value to the Start method. Because the parameters of this method are of the Object type, the type must be forcibly converted.
 

1: static void Main (string [] args)

2:

3 :{

4:

5: Thread thread = new Thread (DoTaskWithParm );

6:

7: thread. Start ("Passing string"); // Start DoTaskWithParm method in a new thread

8:

9: // Do other task in main thread

10:

11 :}

12:

13: static public void DoTaskWithParm (object data)

14:

15 :{

16:

17: // we need to cast the data to appropriate object

18:

19 :}
 

"Async" and "await" keywords
 

The. NET Framework introduces two new keywords for asynchronous programming: "async" and "await ". The Asynchronous Method Using "await" must be declared by the "async" modifier. The "await" keyword modifies the call of An Asynchronous Method. The await operator applies to tasks in an Asynchronous Method to suspend the execution of the method until the task is completed as follows:
 

1: private async static void CallerWithAsync () // async modifier is used

2:

3 :{

4:

5: string result = await GetSomethingAsync (); // await is used before a method call. It suspends

6: // execution of CallerWithAsync () method and control returs to the calling thread that can

// Perform other task.

7:

8: Console. WriteLine (result );

9: // this line wocould not be executed before GetSomethingAsync () // method completes

10:

11 :}
 

The "async" modifier can only be used for methods that return values of the Task type or Void. It cannot be used as the entry point of the main program.
 

The await keyword cannot be used before all methods. To use the "await" keyword, the "waitable" type must be returned. The following are available types:
 

1. Task

2. Task <T>

3. Customize the "wait" type.
 

Task-based asynchronous mode
 

First, we need to declare an Asynchronous Method with the return type of Task or Task <T>. You can create a task in the following ways:
 

1. Task. Factory. StartNew Method: In the previous. NET version (in. NET 4), it is the main method for creating and Starting tasks.

2. Task. Run or Task. Run <T> method: The method from. NET 4.5 has been used. This method is sufficient to meet common conditions.

3. Task. FromResult method: if the result is calculated, you can use this method to create a Task.
 

Create and wait for a task
 

Use the Task. Run <T> method to create a Task. This method runs specific jobs in the thread pool sequentially and returns the job handle. Follow these steps to create an asynchronous task from the synchronization method:
 

1. Assume that the following method is synchronous, but it takes some time to complete it:

1: static string Greeting (string name)

2:

3 :{

4:

5: Thread. Sleep (3000 );

6:

7: return string. Format ("Hello, {0}", name );

8:

9 :}

2. to access this method asynchronously, it must be encapsulated asynchronously. Name it "GreetingAsync ". Add the suffix naming Asynchronous Method for "Async.

1: static Task <string> GreetingAsync (string name)

2:

3 :{

4:

5: return Task. Run <string> () =>

6:

7 :{

8:

9: return Greeting (name );

10:

11 :});

12:

13 :}

3. Now, the Asynchronous Method GreetingAsync can be called using the await keyword

1: private async static void CallWithAsync ()

2:

3 :{

4:

5: // some other tasks

6:

7: string result = await GreetingAsync ("Bulbul ");

8:

9: // We can add multiple "await" in same "async" method

10:

11: // string result1 = await GreetingAsync ("Ahmed ");

12:

13: // string result2 = await GreetingAsync ("Every Body ");

14:

15: Console. WriteLine (result );

16:

17 :}
 

When the "CallWithAsync" method is called, it is executed like the conventional synchronous method until the keyword "await" is encountered. When it executes the keyword to await, it processes the execution and starts to wait until the "GreetingAsync (" Bulbul ")" method is completed. At the same time, the Program Stream will return the caller of the "CallWithAsync" method and continue to execute the caller's task.
 

When the "GreetingAsync (" Bulbul ") method is complete, the" CallWithAsync "method restores other tasks after the" await keyword. In this instance, the code "Console. WriteLine (result)" that will continue to be executed )"
 

4. Use Task continuity: the method of the Task class "ContinueWith" defines the code called after the Task is completed.

1: private static void CallWithContinuationTask ()

2:

3 :{

4:

5: Task <string> t1 = GreetingAsync ("Bulbul ");

6:

7: t1.ContinueWith (t =>

8:

9 :{

10:

11: string result = t. Result;

12:

13: Console. WriteLine (result );

14:

15 :});

16:

17 :}
 

If you use the "ContinueWith" method, you do not need to use the "await" keyword. The Compiler automatically adds the "await" keyword to the appropriate position.
 

Waiting too much ?? Asynchronous methods.
 

Take a look at the following code:
 

1: private async static void CallWithAsync ()

2:

3 :{

4:

5: string result = await GreetingAsync ("Bulbul ");

6:

7: string result1 = await GreetingAsync (& ldquo; Ahmed & rdquo ;);

8:

9: Console. WriteLine (result );

10:

11: Console. WriteLine (result1 );

12:

13 :}
 

There are two waiting function sequences. "GreetingAsync (" Ahmed ")" will be started after the first call "GreetingAsync (" Bulbul ")" is completed. If "result" is independent from the above Code "result1", continuous "awiating" is not a good practice.
 

In this case, you can simplify the call method. You do not need to add multiple "await" keywords. You only need to add the await keyword in one place, as shown below. In this case, all calls to this method can be executed in parallel.
 

1: private async static void MultipleAsyncMethodsWithCombinators ()

2:

3 :{

4:

5: Task <string> t1 = GreetingAsync ("Bulbul ");

6:

7: Task <string> t2 = GreetingAsync ("Ahmed ");

8:

9: await Task. WhenAll (t1, t2 );

10:

11: Console. WriteLine ("Finished both methods. \ n" +

12:

13: "Result 1: {0} \ n Result 2: {1}", t1.Result, t2.Result );

14:

15 :}
 

Here, we use the Task. WhenAll connector. Task. WhenAll creates a Task to complete all provided tasks. The Task class also has other combiner. Task. WhenAny, used when all tasks in the Task chain are completed.
 

Exception Handling
 

You must place the await code block in the try block to catch exceptions.

1: private async static void CallWithAsync ()

2:

3 :{

4:

5: try

6:

7 :{

8:

9: string result = await GreetingAsync ("Bulbul ");

10:

11 :}

12:

13: catch (Exception ex)

14:

15 :{

16:

17: Console. WriteLine (& ldquo; handled {0} & rdquo;, ex. Message );

18:

19 :}

20:

21 :}
 

If there are multiple "await" in the try block, only the first "await" exception will be handled, and other "await" exceptions will not be captured. If you want to capture exceptions for all methods, you cannot use the "await" keyword to call the method and use Task. WhenAll to execute the Task.
 

1: private async static void CallWithAsync ()

2:

3 :{

4:

5: try

6:

7 :{

8:

9: Task <string> t1 = GreetingAsync ("Bulbul ");

10:

11: Task <string> t2 = GreetingAsync ("Ahmed ");

12:

13: await Task. WhenAll (t1, t2 );

14:

15 :}

16:

17: catch (Exception ex)

18:

19 :{

20:

21: Console. WriteLine (& ldquo; handled {0} & rdquo;, ex. Message );

22:

23 :}

24:

25 :}
 

One way to capture all task errors is to declare the task outside the try block, so that you can access it from the try block and check the "IsFaulted" attribute of the task. If an exception exists, the "IsFaulted" attribute value is True, and internal exceptions of the task instance can be captured.
 

There is another better way:

1: static async void showaggrespondexception ()

2:

3 :{

4:

5: Task taskResult = null;

6:

7: try

8:

9 :{

10: Task <string> t1 = GreetingAsync ("Bulbul ");

11:

12: Task <string> t2 = GreetingAsync ("Ahmed ");

13:

14: await (taskResult = Task. WhenAll (t1, t2 ));

15:

16 :}

17:

18: catch (Exception ex)

19:

20 :{

21:

22: Console. WriteLine ("handled {0}", ex. Message );

23:

24: foreach (var innerEx in taskResult. Exception. InnerExceptions)

25:

26 :{

27: Console. WriteLine ("inner exception {0}", nnerEx. Message );}

28 :}

29:

30 :}
 

Cancel task
 

Before that, the thread cannot be canceled if it is called from the thread pool. Now, the Task class provides a method based on the CancellationTokenSource class to cancel a started Task. To cancel a Task, follow these steps:
 

1. asynchronous methods should be excluded from the "CancellationToken" parameter type

2. Create a CancellationTokenSource class instance:

Var cts = new CancellationTokenSource ();

3. Pass CancellationToken, for example:

1: Task <string> t1 = GreetingAsync ("Bulbul", cts. Token );

4. The ThrowIfCancellationRequested () method of CancellationToken must be called during long-running.

1: static string Greeting (string name, CancellationToken token ){

2:

3: Thread. Sleep (3000 );

4:

5: token. ThrowIfCancellationRequested ();

6:

7: return string. Format ("Hello, {0}", name );

8:

9 :}

5. Capture OperationCanceledException exceptions from the waiting tasks.

6. If you cancel the operation by calling the method of the CancellationTokenSource instance, The OperationCanceledException exception will be thrown from the long-running operation. You can also set the cancellation time. The complete code is as follows:

1: static void Main (string [] args)

2:

3 :{

4: CallWithAsync ();

5:

6: Console. ReadKey ();

7:

8 :}

9:

10:

11: async static void CallWithAsync ()

12:

13 :{

14:

15: try

16:

17 :{

18:

19: CancellationTokenSource source = new CancellationTokenSource ();

20:

21: source. CancelAfter (TimeSpan. FromSeconds (1 ));

22:

23: var t1 = await GreetingAsync ("Bulbul", source. Token );

24 :}

25:

26: catch (OperationCanceledException ex)

27:

28 :{

29:

30: Console. WriteLine (ex. Message );

31:

32 :}

33:

34 :}

35:

36: static Task <string> GreetingAsync (string name, CancellationToken token)

37:

38 :{

39:

40: return Task. Run <string> () =>

41:

42 :{

43:

44: return Greeting (name, token );

45:

46 :});

47 :}

48:

49:

50: static string Greeting (string name, CancellationToken token)

51:

52 :{

53:

54: Thread. Sleep (3000 );

55: token. ThrowIfCancellationRequested ();

56:

57: return string. Format ("Hello, {0}", name );

58:

59 :}

60:
 

Parallel Programming
 

. NET 4.5 and later releases the "Parallel class, which is the abstraction of the thread class. Using the "Parallel" class, we can implement parallelism. Parallelism is different from a thread. It uses all available CPUs or kernels. The following two types of parallelism are feasible:
 

Data parallelism: if we have a large collection of data and want to use some operations of each data in parallel, we can use data parallelism. The Parallel class has static For or ForEach to execute data and row, such
 

1: ParallelLoopResult result =

2: Parallel. For (0,100, async (int I) =>

3 :{

4: Console. WriteLine ("{0}, task: {1}, thread: {2}", I,

5: Task. CurrentId, Thread. CurrentThread. ManagedThreadId );

6: await Task. Delay (10 );

7:

8 :});
 

The For or ForEach method can be in multiple threads and the index is unordered.

If you want to stop the parallel For or ForEach method, you can use ParallelLoopState as the parameter and break the loop status as needed to exit the loop.
 

1: ParallelLoopResult result =

2: Parallel. For (0,100, async (int I, ParallelLoopState pls) =>

3 :{

4: Console. WriteLine ("{0}, task: {1}, thread: {2}", I,

5: Task. CurrentId, Thread. CurrentThread. ManagedThreadId );

6: await Task. Delay (10 );

7: if (I> 5) pls. Break ();

8 :});

2. Parallel tasks: If you want to run multiple tasks at the same time, you can call the invoke method of the Parallel class to use the Parallel. Invoke method to receive the array of delegation behavior. For example:

1: static void ParallelInvoke ()

2:

3 :{

4:

5: Parallel. Invoke (MethodOne, MethodTwo );

6:

7 :}

8:
 

Conclusion

This article describes in detail the asynchronous programming technology and details provided by. NET Framework 4.5.

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.