SoFunction
Updated on 2025-03-06

C# implements task-based asynchronous programming mode

1. Continue the task

private async static void CallerWithAsync()
    {
      string result = await GreetingAsync("Stephanie");
      (result);
    }

    static Task<string> GreetingAsync(string name)
    {
      return <string>(() =>
        {
            (10000);
            return name;
        });
    }
    
    GreetingAsyncMethod returns aTask<string>Object。ShouldTask<string>Object包含任务创建的信息,and save until the task is completed。TaskClassicContinueWithMethods define the code that is called after the task is completed。
        private static void CallerWithContinuationTask()
        {

          var t1 = GreetingAsync("Stephanie");


          (t =>
            {
              string result = ;
              (result);
            });


        }

Since await is not used, the thread will not wait in the method and the code of CallerWithContinuationTask() will be executed. ContinueWith will not wait here anymore, so a foreground thread is needed, otherwise it will be closed.

2. Synchronize context

CallerWithAsync and CallerWithContinuationTask methods use different threads at different stages of the method.

static Task<string> GreetingAsync(string name)
        {
          return <string>(() =>
            {
                (10000);
              ("running greetingasync in thread {0} and task {1}", , );
              return name;
            });
        }
        private async static void CallerWithAsync()
        {
          ("started CallerWithAsync in thread {0} and task {1}", , );
          string result = await GreetingAsync("Stephanie");
          (result);
          ("finished GreetingAsync in thread {0} and task {1}", , );
        }
        
        private static void CallerWithContinuationTask()
        {
          ("started CallerWithContinuationTask in thread {0} and task {1}", , );

          var t1 = GreetingAsync("Stephanie");


          (t =>
            {
              string result = ;
              (result);
              ("finished CallerWithContinuationTask in thread {0} and task {1}", , );
            });
        }

Use async and await keywords, when await is completed, you can access the UI thread without any processing. By default, the generated code converts the thread to a thread with a synchronous context. The thread that calls the asynchronous method is assigned to the synchronization context, and will continue to execute after await is completed.
If the same synchronization context is not used, the ConfigureAwait(false) of the Task class must be called. For example, a WPF application has no code that uses UI elements after the await. In this case, avoiding switching to the synchronization context will perform faster.

string s1 = await GreetingAsync("Stephanie").ConfigureAwait(false);

3. Use multiple asynchronous methods

In an asynchronous method, one or more asynchronous methods can be called. How to write code depends on whether the result of one asynchronous method depends on another asynchronous method.

1. Call asynchronous methods in order

In the following example, the second asynchronous method depends on the result of the first asynchronous method, and the await keyword is very useful.

private async static void MultipleAsyncMethods()
{
string s1 = await GreetingAsync("Stephanie");
string s2 = await GreetingAsync(s1);
("Finished both methods.\n Result 1: {0}\n Result 2: {1}", s1, s2);
}

2. Use a combinator

If the second asynchronous method is independent of the first, each asynchronous method may not use await, but assign the return result of each asynchronous method to the Task variable, and it will run faster.

private async static void MultipleAsyncMethodsWithCombinators1()
{
Task<string> t1 = GreetingAsync("Stephanie");
Task<string> t2 = GreetingAsync("Matthias");
await (t1, t2);
("Finished both methods.\n Result 1: {0}\n Result 2: {1}", , );
}
  • The combiner can accept multiple parameters of the same type and return values ​​of the same type.
  • Task is returned only after all tasks passed in methods have been completed.
  • WhenAny returns when one of the tasks passing in methods is completed.

Several overloaded versions are defined. If all tasks return the same type, an array of that type can be used for the results returned by await.

string[] result = await (t1, t2);

4. Convert asynchronous mode

https:///article/Three asynchronous programming modes were discussed.
Not all .NET Framework classes have introduced new asynchronous methods in .NET 4.5. There are also many classes that only provide asynchronous modes of the classes BeginXXX and EndXXX methods. You can use the FromAsync method of the TaskFactory class, which can convert methods that use asynchronous mode to tasks-based asynchronous mode methods.

/Create a delegate,And refer to the synchronization methodGreeting
        private static Func&lt;string, string&gt; greetingInvoker = Greeting;
        
        
        static IAsyncResult BeginGreeting(string name, AsyncCallback callback, object state)
        {
          return (name, callback, state);
        }

        static string EndGreeting(IAsyncResult ar)
        {
          return (ar);
        }
        
        //The first two parameters of the FromAsync method are the delegate type, and the address of BeginGreeting and EndGreeting are passed in.  The last two parameters are the input parameters and the object state parameters.        private static async void ConvertingAsyncPattern()
        {
          string r = await Task&lt;string&gt;.&lt;string&gt;(BeginGreeting, EndGreeting, "Angela", null);
          (r);
        }

5. Error handling

If the asynchronous method is called without waiting, put the asynchronous method in try/catch, the exception will not be caught.

private static void DontHandle()
        {
          try
          {
            ThrowAfter(200, "first");
            // exception is not caught because this method is finished before the exception is thrown
          }
          catch (Exception ex)
          {
            ();
          }
        }
        
        static async Task ThrowAfter(int ms, string message)
        {
            ("xxx");
          await (ms);
          throw new Exception(message);
        }

After the DontHandle method calls ThrowAfter, it will not wait there, and will continue to execute, and no longer maintain a reference to the ThrowAfter method.
Note: The asynchronous method that returns void will never wait. It is best to return a Task type asynchronous method.

1. Exception handling of asynchronous methods

Use the await keyword and put it in try/catch

private static async void HandleOneError()
        {
          try
          {
            await ThrowAfter(2000, "first");
          }
          catch (Exception ex)
          {
            ("handled {0}", );
          }
        }

2. Exception handling of multiple asynchronous methods

If you follow the following code, the second exception will not be thrown. Because the first exception has been thrown, it is directly adjusted to the catch block.

private static async void StartTwoTasks()
        {
          try
          {
            await ThrowAfter(2000, "first");
            await ThrowAfter(1000, "second"); // the second call is not invoked because the first method throws an exception
          }
          catch (Exception ex)
          {
            ("handled {0}", );
          }
        }

Use, regardless of whether the task throws an exception, the two tasks will be completed. So two exceptions will be thrown.
However, you can only see the exception information of the first task passed to the method. Although the second exception will be thrown, it will not be displayed:

private async static void StartTwoTasksParallel()
            {
              Task t1 = null;
              Task t2 = null;
              try
              {
                t1 = ThrowAfter(2000, "first");
                 t2 = ThrowAfter(1000, "second");
                await (t1, t2);
              }
              catch (Exception ex)
              {
                // just display the exception information of the first task that is awaited within WhenAll
                ("handled {0}", );
              }
            }

3. Use AggregateException information to return display exception

Write the returned result into a Task variable. The catch statement only retrieves the exception of the first task, but can access the Exception property of the external task taskResult. The Exception property is AggregateException type. This exception type defines the InnerExceptions property, which contains a list of all exceptions waiting.

private static async void ShowAggregatedException()
        {
          Task taskResult = null;
          try
          {
            Task t1 = ThrowAfter(2000, "first");
            Task t2 = ThrowAfter(1000, "second");
            await (taskResult = (t1, t2));
          }
          catch (Exception ex)
          {
            // just display the exception information of the first task that is awaited within WhenAll
            ("handled {0}", );
            foreach (var ex1 in )
            {
              ("inner exception {0} from task {1}", , );
            }
          }
        }

6. Cancel the asynchronous method

If the background task may run for a long time, it may be possible to cancel the task.
The cancellation of the framework is based on assistive behavior and is not mandatory. A task that runs for a long time requires checking whether it has been cancelled. In this case, its job is to clean up all open resources and end the related work.
Cancel is based on the CancellationTokenSource class, which can be used to send cancel requests. The request is sent to a task that references the CancellationToken class, where the CancellationToken class is associated with the CancellationTokenSource.

private CancellationTokenSource cts = new CancellationTokenSource();
        
        //Add a button to cancel the running task.  use();         private void button5_Click(object sender, EventArgs e)
         {
             if (cts != null)
                 ();
         }
         
        private async void button4_Click(object sender, EventArgs e)
        {
            
            string s =  await AsyncTaskTest();
        }

        //Pass the CancellationToken parameter to the Run method of the Task class.  But you need to check whether the cancel operation is requested.         Task&lt;string&gt; AsyncTaskTest()
        {
            return (() =&gt;
                {
                ();
                    (5000);
                    return "Async completion";
                }
            , );
        }

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.