es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo puedo esperar un enumerado de tareas y detenerme cuando un número determinado de tareas se hayan completado?

Tengo un array de tareas que ejecutan trabajos idénticos, pero usando diferentes parámetros en diferentes servidores. Puede ocurrir que uno de los servidores no responda o sea lento, lo que resultaría en una situación en la que todas las tareas se hayan completado excepto una. En este momento, estoy esperándolas usando Task.WhenAll(), por lo que no tengo otra opción que esperar hasta que se agote el tiempo de espera.

En el caso ideal, todas las tareas se completan dentro del tiempo de espera y puedo recopilar todos los resultados, pero en el otro caso, básicamente quiero esperar:

  • hasta que n tareas se hayan completado
  • durante otros x minutos si se han completado n tareas

Si para el momento en que se hayan completado n tareas y hayamos esperado otros x minutos, no se han completado todas las tareas, quiero recuperar el resultado de las tareas finalizadas.

¿Hay alguna forma de lograr lo anterior?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, puedes lograr el escenario anterior implementando una combinación de Task.WhenAny() y Task.WhenAll(). Aquí tienes un ejemplo de cómo puedes lograr esto utilizando C# y TPL:

    // crea una matriz de tareas en diferentes servidores con diferentes parámetros
    Task[] tasks = new Task[]
    {
        Task.Run(() => DoJobOnServer1(param1)),
        Task.Run(() => DoJobOnServer2(param2)),
        Task.Run(() => DoJobOnServer3(param3)),
        // ...y así sucesivamente...
    };
    
    int n = 2; // número de tareas a esperar
    int timeout = 5; // tiempo de espera en minutos
    
    List<task> completedTasks = new List<task>(); // para almacenar las tareas completadas
    
    while (tasks.Length > 0)
    {
        // espera a que se complete cualquier tarea
        Task completedTask = await Task.WhenAny(tasks);
    
        // elimina la tarea completada de la matriz de tareas
        tasks = tasks.Where(t => t != completedTask).ToArray();
    
        // agrega la tarea completada a la lista de tareas completadas
        completedTasks.Add(completedTask);
    
        // verifica si se han completado el número requerido de tareas
        if (completedTasks.Count >= n)
        {
            // espera x minutos antes de verificar si todas las tareas se han completado
            bool allCompleted = await Task.WhenAll(tasks.Concat(completedTasks)).WaitAsync(TimeSpan.FromMinutes(timeout));
    
            if (allCompleted)
            {
                // todas las tareas se han completado dentro del tiempo de espera
                break;
            }
            else
            {
                // algunas tareas aún se están ejecutando después del tiempo de espera
                // obtén los resultados de las tareas completadas
                foreach (Task task in completedTasks)
                {
                    dynamic result = await task;
                    // procesa el resultado...
                }
    
                // sal del bucle
                break;
            }
        }
    }
    
    // obtén los resultados de todas las tareas completadas
    foreach (Task task in completedTasks.Concat(tasks))
    {
        dynamic result = await task;
        // procesa el resultado...
    }
    

    En este ejemplo, primero creamos una matriz de tareas que ejecutan trabajos idénticos pero con diferentes parámetros en diferentes servidores. Luego, definimos el número de tareas a esperar (n) y el tiempo de espera en minutos (timeout). También creamos una lista vacía para almacenar las tareas completadas.

    Luego, entramos en un bucle donde esperamos a que se complete cualquier tarea utilizando Task.WhenAny(). Una vez que una tarea se completa, la eliminamos de la matriz de tareas y la agregamos a la lista de tareas completadas. Luego verificamos si se han completado el número requerido de tareas. Si no, continuamos esperando a que se completen más tareas.

    Si se han completado el número requerido de tareas, esperamos otros x minutos utilizando el método de extensión WaitAsync() de la biblioteca TPL Dataflow. Este método nos permite esperar un período de tiempo especificado sin bloquear el hilo de llamada. Si todas las tareas se han completado dentro del tiempo de espera, salimos del bucle y obtenemos los resultados de todas las tareas completadas utilizando Task.WhenAll(). Si algunas tareas aún se están ejecutando después del tiempo de espera, obtenemos los resultados de las tareas completadas y salimos del bucle.

    Finalmente, obtenemos los resultados de todas las tareas completadas (incluyendo las que aún se estaban ejecutando después del tiempo de espera) y los procesamos según sea necesario.

Comments are closed.