C # -Async palabra clave (método asincrónico)

palabra clave asincrónica (método asincrónico)

La palabra clave async es exclusiva de C #. Java no tiene tal cosa.
async es una palabra clave contextual en el mundo de C #. El compilador la reconoce automáticamente como una palabra clave solo cuando modifica un método, y puede usarse para cualquier otro propósito, como nombres de variables en otros lugares del código.
La palabra clave async se usa para modificar dos tipos de métodos: expresiones lambda o métodos asincrónicos.
Un método con modificación asíncrona se denomina método asíncrono, como por ejemplo:

public async Task<int> ExampleMethodAsync()  
{
    
      
     // (1) To do some code here synchronously...
    await .....//  (2) To do something asynchronously....
    // (3) To do some code here after awiat code...
} 

Al igual que el método anterior ExampleMethodAsync (), al abuelo Microsoft le gusta agregar un sufijo Async después de definir el nombre de una función asincrónica (esto no es necesario, agregar o no agregar un compilador no reportará un error ni afectará la función asincrónica), cuéntanos Este método es un método asincrónico. Cuando definimos métodos asincrónicos nosotros mismos, también podemos copiar este hábito de Microsoft. Dentro del método modificado
asíncrono , debería haber una palabra clave de espera y las dos palabras clave generalmente aparecen en pares. Por supuesto, si accidentalmente olvidamos escribir una expresión o declaración de espera , este método asincrónico se ejecuta de manera síncrona por defecto. Al mismo tiempo, el compilador nos preguntará amablemente si nos perdimos la espera . Además, dentro del método async , puede haber varias declaraciones de espera . Las declaraciones ejecutadas por
awiat son generalmente tareas que consumen mucho tiempo (es decir, algunas operaciones que bloquearán el hilo principal, como obtener respuestas Http, escribir documentos, guardar bases de datos, etc.), de lo contrario no hay necesidad de asincronía.
Tome el ejemplo anterior como ejemplo (asumiendo que el await en el ejemplo es el primer await ), el proceso de ejecución del método asincrónico (una mirada aproximada):

  1. Después de que el hilo principal ingresa al método ExampleMethodAsync (), ejecuta (1) primero; si hay una declaración para crear Task o Task <TResult> en (1), o llamar a otros métodos asincrónicos (el valor de retorno es Task o Task <TResult>) Para la conveniencia de la descripción, todos lo llamamos instrucción de creación de tarea; por ejemplo, cree una tarea o tarea <TResult> directamente:
var tsk = Task.Run(()=>{
    
    
	Thread.Sleep(1000);
	Console.Writeline("Do another job asynchronously.");
});

O llame a otro método asincrónico:

Task<string> getStringTask = client.GetStringAsync("https://docs.microsoft.com/dotnet");

Entonces, la tarea asincrónica ya ha comenzado a ejecutarse cuando se llama a la instrucción de creación de la tarea (la llamada de instrucción en sí está en el hilo principal y la tarea interna se ejecuta en un nuevo hilo), es decir, el hilo asíncrono se ha iniciado en este momento , Debido a que se inicia de forma asincrónica, no evita que el hilo principal continúe cayendo;

  1. A continuación, el hilo principal se ejecutará secuencialmente al primer await dentro del método async. Si el primer await llama a un método async, entonces el programa principal continúa ingresando a la ejecución del método hasta que encuentra una tarea en espera. El hilo saldrá del método ExampleMethodAsync; por ejemplo:
	static void  Main(string[] args)
	{
    
    
		// do something...
		ExampleMethodAsync();
		// do someting else...
	}
    public static async void ExampleMethodAsync()
    {
    
    
        // (1) 执行一些任务Do2Async()前准备的事情...
        await Do2Async(); // (2)
        // (3) 运行一些Do2Async()执行完之后的事情...
    }
	public static Task Do2Async()
	{
    
    
	    // 执行一些t任务执行前的事情,比如任务的准备...
	    Task t = Task.Run(()=>{
    
    
	    // 异步任务中执行费时的事情...
	    });
	    // 运行一些与t无关的事情...
	    await t;
	    // 在这里执行一些t任务执行完相关的事情...
	}

La persona que llama (es decir, el hilo principal donde se encuentra main) se ejecutará hasta la línea 20 antes de saltar del método ExampleMethodAsync (), no en la línea 10.

  1. El (3) restante en el método ExampleMethodAsync () se ejecuta después de que se ejecuta la parte await (2).
  2. Supongamos que hay un segundo, tercer ... awiat en ExampleMethodAsync (), porque el programa principal ya ha saltado, y las esperas posteriores se ejecutarán secuencialmente en subprocesos asincrónicos.

El método asincrónico puede tener los siguientes tres tipos de devolución:

  • Tarea
  • Tarea <TResult>
  • El tipo de retorno vacío se usa generalmente en controladores de eventos o en situaciones en las que solo necesita la ejecución de la tarea y no le importan los resultados de la ejecución de la tarea.
  • Cualquier otro tipo con el método GetAwaiter (desde C # 7.0)

Tenga en cuenta que no podemos esperar (awiat) por un método void asincrónico.

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

namespace test
{
    
    
    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  Hello, I am Caller!");
            DoAsync();
            Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  Hello, I am Caller too!");
            Console.Read();
        }
        public static async void DoAsync()
        {
    
    
            System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  In DoAsync(), before SunAsync()");
            await SunAsync();
            System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  After SunAsync(), DoAsync() End.");
        }
        public static async Task SunAsync()
        {
    
    
            var t = Task.Run(()=>{
    
    
                    System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  New Task~");
                    for(int i=0 ; i<10; i++)
                    {
    
    
                        Thread.Sleep(1000);
                        System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  I am playing game...");                    
                    }
                });
            System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  After Task, before await.");
            await t;
            System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  After await, before SunAsync() exit.");
        }
    }
}

El resultado en este momento:

ThreadID:1  Hello, I am Caller!
ThreadID:1  In DoAsync(), before SunAsync()
ThreadID:1  After Task, before await.
ThreadID:4  New Task~
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:4  I am playing game...
ThreadID:1  After await, before SunAsync() exit.
ThreadID:1  After SunAsync(), DoAsync() End.
ThreadID:1  Hello, I am Caller too!
Lea este código y los resultados con atención, y tenga en cuenta que este código es un método ansync void incrustado en un método de tarea ansync. Preste atención a la experiencia, no significa que el método DoAsync () se salga inmediatamente tan pronto como encuentra el programa principal await (el llamador del método ansync), pero la ejecución llega a la línea 33 y salta cuando encuentra la primera tarea. A partir del número ThreadID de salida de este ejemplo, se puede ver que el contenido después de la línea 33 en espera se ejecuta en un nuevo hilo (4 hilos). El contenido antes de la línea 33 en espera se ejecuta en el hilo principal (1 hilo).

Si cambia el código SunAsync () a (agregue un Thread.Sleep (150000) antes de await):


  public static async Task SunAsync()
        {
    
    
            var t = Task.Run(()=>{
    
    
                    System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  New Task~");
                    for(int i=0 ; i<10; i++)
                    {
    
    
                        Thread.Sleep(1000);
                        System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  I am playing game...");                    
                    }
                });
            System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  After Task, before await.");
            Thread.Sleep(15000); //主线程睡15秒
            await t;
            System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId}  After await, before SunAsync() exit.");
        }

ThreadID: 1 ¡Hola, soy la persona que llama!
ThreadID: 1 En DoAsync (), antes de SunAsync ()
ThreadID: 1 Después de la tarea, antes de esperar.
ThreadID: 4 Nueva tarea ~
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 I estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 4 Estoy jugando ...
ThreadID: 1 Después de await, antes de salir de SunAsync ().
ThreadID: 1 después de SunAsync (), DoAsync () End.
ThreadID: 1 Hola, ¡yo también soy la persona que llama!

Debido a que la tarea de Task.Run () finaliza antes de que se ejecute para esperar, por lo tanto, el contenido después de esperar todavía se ejecuta en el hilo principal (1 hilo). Este ejemplo nos dice que si la tarea se ha ejecutado antes de await, el contenido posterior a await se seguirá ejecutando en el hilo original.

En resumen, el llamador del método asíncrono sale del cuerpo del método asíncrono cuando encuentra una tarea en espera real. Generalmente, las cosas que no tienen nada que ver con las tareas asincrónicas se procesan antes de await (esta parte del código es ejecutada por el hilo donde se encuentra el llamador del método asincrónico), y el código posterior a await se ocupa de las cosas después de que se procesa la tarea asincrónica, por lo que esta parte del código se puede procesar. Cosas relacionadas con las tareas asincrónicas (esta parte generalmente se ejecuta en un subproceso asíncrono recién creado, a menos que la tarea se haya ejecutado rápidamente antes de llamar a await, entonces esta parte aún se puede ejecutar en el subproceso que llama) .

Supongo que te gusta

Origin blog.csdn.net/MrLsss/article/details/106895685
Recomendado
Clasificación