Saltar al contenido

Usando async/await o task en el controlador web api (.net core)

Nuestros mejores programadores han agotado sus provisiones de café, investigando diariamente por la respuesta, hasta que Víctor halló el hallazgo en GitLab así que en este momento la compartimos aquí.

Solución:

Esto funciona bien, sin embargo, me pregunto si usar tareas es la mejor solución aquí. ¿Usar async/await sería una mejor idea y una forma más aceptada?

Si, absolutamente. Hacer un procesamiento paralelo en ASP.NET consume múltiples subprocesos por solicitud, lo que puede afectar gravemente su escalabilidad. El procesamiento asíncrono es muy superior para E/S.

Usar async, primero comience con su llamada de nivel más bajo, en algún lugar dentro de su servicio. Probablemente esté haciendo una llamada HTTP en algún momento; cambie eso para usar llamadas HTTP asincrónicas (por ejemplo, HttpClient). Entonces deja async crecer naturalmente desde allí.

Eventualmente, terminará con asincrónico getdata1Async, getdata2Asyncy getdata3Async métodos, que se pueden consumir simultáneamente como tales:

[HttpGet]
public async Task myControllerAction()

  var t1 = service.getdata1Async();
  var t2 = service.getdata2Async();
  var t3 = service.getdata3Async();
  await Task.WhenAll(t1, t2, t3);

  var data = new returnObject
  
    d1 = await t1,
    d2 = await t2,
    d3 = await t3
  ;

  return Ok(data);

Con este enfoque, mientras las tres llamadas de servicio están en curso, myControllerAction usos cero hilos en lugar de cuatro.

[HttpGet]
public async Task GetAsync()
      
    var t1 = Task.Run(() => service.getdata1());
    var t2 = Task.Run(() => service.getdata2());
    var t3 = Task.Run(() => service.getdata3());

    await Task.WhenAll(t1, t2, t3);

    var data = new returnObject
    
        d1 = t1.Status == TaskStatus.RanToCompletion ? t1.Result : null,
        d2 = t2.Status == TaskStatus.RanToCompletion ? t2.Result : null,
        d3 = t3.Status == TaskStatus.RanToCompletion ? t3.Result : null
    ;

   return Ok(data);

  1. Su hilo de acción está actualmente bloqueado cuando está esperando tareas. Utilizar TaskWhenAll para devolver el objeto de tarea esperable. Por lo tanto, con el método asíncrono puede esperar tareas en lugar de bloquear el hilo.
  2. En lugar de crear variables locales y asignarlas en tareas, puede usar Task para devolver resultados del tipo requerido.
  3. En lugar de crear y ejecutar tareas, utilice Task.Run método
  4. Recomiendo usar la convención para los nombres de acción: si la acción acepta la solicitud GET, su nombre debe comenzar con Get
  5. A continuación, debe verificar si las tareas se completaron con éxito. Se realiza comprobando el estado de la tarea. En mi muestra usé null valores para las propiedades del objeto de retorno si algunas de las tareas no se completan correctamente. Puede usar otro enfoque, por ejemplo, devolver un error si algunas de las tareas fallaron.

Según tengo entendido, desea que esto se ejecute en paralelo, por lo que no creo que haya ningún problema con su código. Como mencionó Gabriel, podrías esperar a que terminen las tareas.

[HttpGet]
public async Task myControllerAction()
      
  var data1 = new sometype1();
  var data2 = new sometype2();
  var data3 = new List();

  var t1 = Task.Run(() =>  data1 = service.getdata1(); );
  var t2 = Task.Run(() =>  data2 = service.getdata2(); );
  var t3 = Task.Run(() =>  data3 = service.getdata3(); );

  await Task.WhenAll(t1, t2, t3); // otherwise a thread will be blocked here

  var data = new returnObject
  
      d1 = data1,
      d2 = data2,
      d2 = data3
  ;

 return Ok(data);

También puede usar los resultados de las tareas para guardar algunas líneas de códigos y hacer que el código en general sea “mejor” (ver comentarios):

[HttpGet]
public async Task myControllerAction()
      
  var t1 = Task.Run(() => service.getdata1() );
  var t2 = Task.Run(() => service.getdata2() );
  var t3 = Task.Run(() => service.getdata3() );

  await Task.WhenAll(t1, t2, t3); // otherwise a thread will be blocked here

  var data = new returnObject
  
      d1 = t1.Result,
      d2 = t2.Result,
      d2 = t3.Result
  ;

 return Ok(data);

Comentarios y calificaciones

Si conservas alguna desconfianza o capacidad de refinar nuestro división te sugerimos escribir una disquisición y con gusto lo ojearemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *