understanding - task.run c#
Task.Run vs. direct async call para iniciar métodos asincrónicos de larga ejecución (2)
Mi principal comprensión de la diferencia entre estos dos métodos es que el primero inicialmente comenzará a bucles en un subproceso de grupo de subprocesos, mientras que el segundo se ejecutará en el subproceso actual hasta que el primero espere. ¿Es esto cierto?
Sí, eso es verdad.
En su escenario, parece que no hay necesidad de usar Task.Run
, prácticamente no hay ningún código entre la llamada al método y la primera await
, por lo que PollLoop()
volverá casi de inmediato. Vaciar innecesariamente una tarea en otra tarea solo hace que el código sea menos legible y agrega sobrecarga. Prefiero usar el segundo enfoque.
En cuanto a otras consideraciones (por ejemplo, manejo de excepciones), creo que los dos enfoques son equivalentes.
El objetivo de usar asincronización para este propósito es que no necesitamos un hilo de sondeo dedicado y, sin embargo, la lógica es (para mí) más fácil de entender que el uso de algo como un temporizador directamente
Como nota al margen, esto es más o menos lo que haría un temporizador de todos modos. De hecho, Task.Delay
se implementa con un temporizador.
Varias veces, me he encontrado escribiendo métodos asincrónicos de larga ejecución para cosas como los loops de sondeo. Estos métodos pueden verse más o menos así:
private async Task PollLoop()
{
while (this.KeepPolling)
{
var response = await someHttpClient.GetAsync(...).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// do something with content
await Task.Delay(timeBetweenPolls).ConfigureAwait(false);
}
}
El objetivo de usar asincronización para este propósito es que no necesitamos un hilo de sondeo específico y, sin embargo, la lógica es (para mí) más fácil de entender que el uso de algo como un temporizador directamente (también, no hay necesidad de preocuparse por la reentrada).
Mi pregunta es, ¿cuál es el método preferido para lanzar un bucle de este tipo desde un contexto sincrónico? Puedo pensar en al menos 2 enfoques:
var pollingTask = Task.Run(async () => await this.PollLoop());
// or
var pollingTask = this.PollLoop();
En cualquier caso, puedo responder a las excepciones usando ContinueWith (). Mi principal comprensión de la diferencia entre estos dos métodos es que el primero inicialmente comenzará a bucles en un subproceso de grupo de subprocesos, mientras que el segundo se ejecutará en el subproceso actual hasta que el primero espere. ¿Es esto cierto? ¿Hay otras cosas que considerar o mejores enfoques para probar?
Mi principal comprensión de la diferencia entre estos dos métodos es que el primero inicialmente comenzará a bucles en un subproceso de grupo de subprocesos, mientras que el segundo se ejecutará en el subproceso actual hasta que el primero espere. ¿Es esto cierto?
Sí. Un método asíncrono devuelve su tarea a su llamador en la primera espera de un awaitable que aún no se ha completado.
Por convención, la mayoría de los métodos asíncronos regresan muy rápido. La tuya también lo hace porque await someHttpClient.GetAsync
que se alcance algo de await someHttpClient.GetAsync
muy rápidamente.
No tiene sentido mover el comienzo de este método asíncrono al grupo de subprocesos. Agrega sobrecarga y ahorra casi ninguna latencia. Ciertamente no ayuda a la producción o al comportamiento de escalado.
Usando una lambda asíncrona aquí ( Task.Run(async () => await this.PollLoop())
) es especialmente inútil. Simplemente envuelve la tarea devuelta por PollLoop
con otra capa de tareas. sería mejor decir Task.Run(() => this.PollLoop())
.