Clase de tarea de C#: aprendizaje de subprocesos múltiples 2

El artículo anterior ( Clase C# Thread - aprendizaje de subprocesos múltiples 1 ) habló sobre la clase Thread de subprocesos múltiples. A continuación, continúe aprendiendo otro punto de conocimiento más importante sobre subprocesos múltiples: la clase Task. Si tiene tiempo, también se recomienda para leer el artículo anterior El artículo podría ser útil.

Thread thread es una herramienta de bajo nivel utilizada para crear concurrencia, tiene algunas limitaciones, en particular:

  • Aunque es conveniente pasar datos al iniciar un subproceso, es difícil obtener un valor de retorno del subproceso al unirse.
  • Es posible que sea necesario configurar algunos campos compartidos.
  • Si la operación arroja una excepción, es problemático distribuir y propagar la excepción
  • No hay forma de decirle a un subproceso que comience un trabajo adicional cuando finaliza, debe realizar una operación de unión (bloqueando el subproceso actual en el proceso)
  • Difícil de usar concurrentes más pequeños (concurrentes) para componer concurrentes grandes

La clase Task puede resolver muy bien los problemas anteriores, es una abstracción de alto nivel: representa una operación concurrente (concurrent), que puede o no ser soportada por Thread.

  • Las tareas se pueden componer (puede usar la continuación para encadenarlas).
  • Las tareas pueden usar grupos de subprocesos para reducir la latencia de inicio.
  • Con TaskCompletionSource, Tasks puede aprovechar las devoluciones de llamada para evitar por completo el uso de subprocesos mientras se esperan operaciones vinculadas a E/S.

Hay muchas maneras de establecer subprocesos múltiples para Task, que se explicarán a través del código a continuación . El código puede ser un poco largo, pero es más fácil de entender si se divide en bloques, ya que se combinan varios métodos para la introducción, por lo que el código completo y los resultados de salida son relativamente largos.

Vaya directamente al código, seguido de un análisis del código:

using System;
using System.Threading; 
using System.Threading.Tasks;

namespace ch_Task
{
    
    
    class Program
    {
    
    
        static void CallTask2(string name)
        {
    
    
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} beginning! ---name:" + name);
            for (int i = 1; i <= 5; i++)
            {
    
    
                Thread.Sleep(500);
                Console.WriteLine($"{
      
      i.ToString()} ---name:task2");
            }
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} finished! ---name:" + name);
        }
        public static void CallTask3()
        {
    
    
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} beginning! ---name:task3");
            for (int i = 1; i <= 5; i++)
            {
    
    
                Thread.Sleep(500);
                Console.WriteLine($"{
      
      i.ToString()} ---name:task3");
            }
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} finished! ---name:task3");
        }
        public static void CallTask3Continue(Task t)
        {
    
    
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} beginning! ---name:task3.continue");
            for (int i = 1; i <= 5; i++)
            {
    
    
                Thread.Sleep(500);
                Console.WriteLine($"{
      
      i.ToString()} ---name:task3.continue");
            }
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} finished! ---name:task3.continue");
        }

        async static void task4()
        {
    
    
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} beginning! ---name:task4");
            for (int i = 1; i<= 5; i++)
           {
    
    
              Console.WriteLine($"{
      
      i.ToString()} ---name:task4");
              await Task.Delay(500);
            }
            Console.WriteLine($"taskID:{
      
      Task.CurrentId} finished! ---name:task4");
        }

        static void Main(string[] args)
        {
    
    
            //-----------方式1-----------------
            Task task1 = new Task(() =>
            {
    
    
                Console.WriteLine($"taskID:{
      
      Task.CurrentId} beginning! ------name:task1");
                
                for(int i=1;i<=5;i++)
                {
    
       
                    Thread.Sleep(500);
                    Console.WriteLine($"{
      
      i.ToString()} ---name:task1");
                }
                Console.WriteLine($"taskID:{
      
      Task.CurrentId} finished! ------name:task1");
            });
            task1.Start();

            // program execution after task1 finish
            task1.ContinueWith((task) =>
            {
    
    
                Console.WriteLine($"taskID:{
      
      task.Id}.continue begin and this task id is {
      
      Task.CurrentId}");
               
                for (int i = 1; i <= 5; i++)
                {
    
     
                    Thread.Sleep(500);
                    Console.WriteLine($"{
      
      i.ToString()} ---name:task1.continue");
                }
                Console.WriteLine($"taskID:{
      
      Task.CurrentId} finished! ------name:task{
      
      task.Id}.continue");
            });

            //-------------方式2----------------
            var task2 = new Task(() => CallTask2("Task2"));
            task2.Start();

            //------------方式3------------
            Task task3 = new Task(CallTask3);
            task3.Start();
            Task task3Continue = task3.ContinueWith(CallTask3Continue);

            task3Continue.Wait(); // 阻塞主线程,直到task3Continue 线程执行结束
            //-------------方式4-------------
            task4();

            Console.ReadKey();
        }
    }
 }

La salida es:

taskID:1 beginning! ------name:task1
taskID:3 beginning! ---name:Task2
taskID:4 beginning! ---name:task3
1 ---name:task1
1 ---name:task2
1 ---name:task3
2 ---name:task1
2 ---name:task2
2 ---name:task3
3 ---name:task1
3 ---name:task2
3 ---name:task3
4 ---name:task1
4 ---name:task3
4 ---name:task2
5 ---name:task1
taskID:1 finished! ------name:task1
taskID:1.continue begin and this task id is 2
5 ---name:task3
5 ---name:task2
taskID:4 finished! ---name:task3
taskID:3 finished! ---name:Task2
taskID:5 beginning! ---name:task3.continue
1 ---name:task1.continue
1 ---name:task3.continue
2 ---name:task1.continue
2 ---name:task3.continue
3 ---name:task3.continue
3 ---name:task1.continue
4 ---name:task3.continue
4 ---name:task1.continue
5 ---name:task3.continue
5 ---name:task1.continue
taskID:5 finished! ---name:task3.continue
taskID:2 finished! ------name:task1.continue
taskID: beginning! ---name:task4
1 ---name:task4
2 ---name:task4
3 ---name:task4
4 ---name:task4
5 ---name:task4
taskID: finished! ---name:task4

Analicemos los resultados de salida:
mirando directamente la parte de la función principal, puede ver que hay seis subprocesos task1, task1.continue, task2, task3, task3.continue y task4, y se utilizan cuatro métodos respectivamente:

task1 使用 : Task task1 = new Task(() =>{
    
     } );直接去创建子线程。其实,这个运行的话可以简化即:
将下面代码:

Task task1 = new Task(() =>{
    
     } );
task1.start()

换成 : Task.Run(() =>{
    
     } ); 即可
task2 使用: var task2 = new Task(() => CallTask2("Task2")) 创建子线程。
task3 使用: Task task3 = new Task(CallTask3);直接创建子线程
task4 使用异步方法去创建子线程,关键词:async, 可以看到在task4之前,使用了task3Continue.Wait();  
这个语句可以用来阻塞主线程,直到task3Continue 线程执行结束后才会 task4线程的定义与运行。

另外,可以看到,在别的task使用延时用的都是 Thread.Sleep(500); 而使用异步方法创建的子线程在使用延时
的时候使用的是 await Task.Delay(500);这一点需要留意。
task1.continue 线程 即 task1.ContinueWith((task) => {
    
    })在task1 完全执行结束后才执行,
同理
task3.continue在task3 完全结束之后才执行。

Task.ContinueWith((task) => {
    
    })可以将子线程串联起来

Supongo que te gusta

Origin blog.csdn.net/ZhangJingHuaJYO/article/details/124364408
Recomendado
Clasificación