c# - Ejecute dos tareas asíncronas en paralelo y recopile resultados en.NET 4.5
asynchronous task-parallel-library (6)
He estado intentando por un tiempo obtener algo que pensé que sería simple de trabajar con .NET 4.5
Quiero disparar dos tareas de ejecución larga al mismo tiempo y recoger el
da como resultado la mejor forma de C # 4.5 (RTM)
Lo siguiente funciona pero no me gusta porque:
- Quiero que
Sleep
sea un método asíncrono para que puedaawait
otros métodos - Se ve torpe con
Task.Run()
- ¡No creo que esto siquiera esté usando nuevas funciones de lenguaje!
Código de trabajo:
public static void Go()
{
Console.WriteLine("Starting");
var task1 = Task.Run(() => Sleep(5000));
var task2 = Task.Run(() => Sleep(3000));
int totalSlept = task1.Result + task2.Result;
Console.WriteLine("Slept for a total of " + totalSlept + " ms");
}
private static int Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
Thread.Sleep(ms);
Console.WriteLine("Sleeping for " + ms + " FINISHED");
return ms;
}
Código no funcional:
Actualización: esto realmente funciona y es la forma correcta de hacerlo, el único problema es el Thread.Sleep
Este código no funciona porque la llamada a Sleep(5000)
inicia inmediatamente la tarea que se ejecuta, por lo que la Sleep(1000)
no se ejecuta hasta que se completa. Esto es cierto a pesar de que Sleep
es async
y no estoy usando .Result
o llamando .Result
demasiado pronto.
Pensé que tal vez haya una manera de obtener una Task<T>
no ejecutable llamando a un método async
para poder llamar a Start()
en las dos tareas, pero no puedo entender cómo obtener una Task<T>
de llamar a un método asíncrono.
public static void Go()
{
Console.WriteLine("Starting");
var task1 = Sleep(5000); // blocks
var task2 = Sleep(1000);
int totalSlept = task1.Result + task2.Result;
Console.WriteLine("Slept for " + totalSlept + " ms");
}
private static async Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
Thread.Sleep(ms);
return ms;
}
¡Es fin de semana !
public static void Go() {
Console.WriteLine("Start fosterage.../n");
var t1 = Sleep(5000, "Kevin");
var t2 = Sleep(3000, "Jerry");
var result = Task.WhenAll(t1, t2).Result;
Console.WriteLine("/nMy precious spare time last for only {0}ms", result.Max());
Console.WriteLine("Press any key and take same beer...");
Console.ReadKey();
}
private static async Task<int> Sleep(int ms, string n) {
Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms);
await Task.Delay(ms);
Console.WriteLine("{0} waked up after {1}ms :(", n, ms);
return ms;
}
Tarea ordinaria . Ejemplo de fábrica :
private static Task<int> Sleep(int ms, string n) {
return Task.Factory.StartNew(() => {
Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms);
Thread.Sleep(ms);
Console.WriteLine("{0} waked up after {1}ms :(", n, ms);
return ms;
});
}
Ejemplo misterioso TaskCompletionSource :
private static Task<int> Sleep(int ms, string n) {
var tcs = new TaskCompletionSource<int>();
Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms);
var t = Task.Factory.StartNew(() => {
Thread.Sleep(ms);
Console.WriteLine("{0} waked up after {1}ms :(", n, ms);
tcs.SetResult(ms);
});
return tcs.Task;
}
Debe usar Tarea.Delay en lugar de Sleep para la programación asincrónica y luego use Tarea. Cuando todo se combina con los resultados de la tarea. Las tareas se ejecutarían en paralelo.
public class Program
{
static void Main(string[] args)
{
Go();
}
public static void Go()
{
GoAsync();
Console.ReadLine();
}
public static async void GoAsync()
{
Console.WriteLine("Starting");
var task1 = Sleep(5000);
var task2 = Sleep(3000);
int[] result = await Task.WhenAll(task1, task2);
Console.WriteLine("Slept for a total of " + result.Sum() + " ms");
}
private async static Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount);
await Task.Delay(ms);
Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount);
return ms;
}
}
Este artículo ayudó a explicar muchas cosas. Está en estilo de preguntas frecuentes.
Preguntas frecuentes asincrónicas / esperadas
Esta parte explica por qué Thread.Sleep
ejecuta en el mismo hilo original, lo que lleva a mi confusión inicial.
¿La palabra clave "async" causa la invocación de un método para hacer cola en ThreadPool? Para crear un nuevo hilo? Para lanzar un cohete a Marte?
No. No. Y no. Ver las preguntas anteriores. La palabra clave "async" indica al compilador que "await" puede usarse dentro del método, de modo que el método puede suspenderse en un punto de espera y su ejecución se reanuda de forma asíncrona cuando finaliza la instancia esperada. Esta es la razón por la cual el compilador emite una advertencia si no hay "espera" dentro de un método marcado como "async".
Mientras que su método Sleep
es asincrónico, Thread.Sleep
no lo es. La idea de asincronizar es reutilizar un único hilo, no iniciar varios hilos. Debido a que ha bloqueado el uso de una llamada sincrónica a Thread.Sleep, no va a funcionar.
Thread.Sleep
que Thread.Sleep
es una simplificación de lo que realmente quieres hacer. ¿Puede su implementación real codificarse como métodos asíncronos?
Si necesita ejecutar varias llamadas de bloqueo sincrónicas, ¡busque en otro lado, creo!
Para responder a este punto:
Quiero que Sleep sea un método asíncrono para que pueda esperar otros métodos
quizás puedas reescribir la función Sleep
esta manera:
private static async Task<int> Sleep(int ms)
{
Console.WriteLine("Sleeping for " + ms);
var task = Task.Run(() => Thread.Sleep(ms));
await task;
Console.WriteLine("Sleeping for " + ms + "END");
return ms;
}
static void Main(string[] args)
{
Console.WriteLine("Starting");
var task1 = Sleep(2000);
var task2 = Sleep(1000);
int totalSlept = task1.Result +task2.Result;
Console.WriteLine("Slept for " + totalSlept + " ms");
Console.ReadKey();
}
corriendo este código saldrá:
Starting
Sleeping for 2000
Sleeping for 1000
*(one second later)*
Sleeping for 1000END
*(one second later)*
Sleeping for 2000END
Slept for 3000 ms
async Task<int> LongTask1() { ... }
async Task<int> LongTask2() { ... }
...
{
Task<int> t1 = LongTask1();
Task<int> t2 = LongTask2();
await Task.WhenAll(t1,t2);
//now we have t1.Result and t2.Result
}