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 esperar a que cualquier operación asincrónica finalice y obtener su índice?

Necesito esperar por múltiples tareas asíncronas pero no quiero ningún comportamiento de bloqueo, así que revisé esta respuesta y creé un algoritmo asíncrono no bloqueante. Aquí está mi código:

std::vector<><int>> asyncs;
for (int i{0}; i < 4; i++) {
  asyncs.push_back(std::async(
    std::launch::async,
    do_something) // do_something() espera durante una cantidad aleatoria de milisegundos y devuelve el tiempo esperado
  );
}

for (auto&& fut:asyncs) {
    std::cout << "Tiempo de espera: " << fut.get() << std::endl;
}

Entonces, cuando lo ejecuto, obtengo la siguiente salida:

Tiempo de espera: 1544
Tiempo de espera: 3350
Tiempo de espera: 2915
Tiempo de espera: 2775

Sin embargo, no sé en qué orden se iniciaron. ¿Se inició primero la async que se ejecutó durante 1544ms o al último? ¿Se inició 2775ms segundo o tercero? Antes de usar métodos no bloqueantes, haría:

for (int i{0}; i < 4; i++) int value = asyncs[i].get();

Esto me permitía saber exactamente qué tarea había terminado porque era ese índice en el vector. Estoy codificando para la velocidad, por lo que no quiero buscar en el vector cada vez que una async termina. Y no quiero hacer nada descuidado como enviar el índice como parámetro y devolver una tupla.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Como experto en TI especializado en C++, asíncrono y vector, puedes modificar el código de tareas asincrónicas no bloqueantes para conocer cuál tarea ha finalizado sin comportamiento de bloqueo. Una posible solución es usar un mapa para almacenar cada futuro junto con su índice correspondiente en el vector. Aquí hay un ejemplo de cómo se puede hacer:

     std::vector <std::futuro></std::futuro><int>> asyncs;
     std::map <><int>*, int> future_index_map;
    
     for(const int i{0}; i < 4; i++) {
         auto future = std::async (std::launch::async, do_something);
         asyncs.push_back (std::move (future));
         future_index_map [&asyncs.back()] = i; // Agrega el futuro y su índice al mapa
     }
    
     while(!asyncs.empty()) {
         auto it = std :: begin (asyncs);
         while (it! = std :: end (asyncs)) {
             auto status = it->wait_for (std :: chrono :: seconds(0));
             if (status == std :: future_status :: ready) {
                 int index = future_index_map [& (*it)]; // Recupera el índice del mapa
                 std::cout << "Tarea " << índice << " finalizada con tiempo de espera: " << it -> get () << std::endl;
                 it = asyncs.erase (it); // Elimina el futuro del vector
             } else {
                 ++ it;
             }
         }
     }
    

    Este código crea un mapa future_index_map que mapea cada futuro con su índice correspondiente en el vector. En el bucle que espera a que las tareas finalicen, primero verifica el estado de cada futuro con un tiempo de espera cero utilizando wait_for(). Si un futuro está listo, recupera su índice del mapa y luego lo elimina del vector utilizando erase(). Finalmente, imprime el índice y el tiempo de espera.

    De esta manera, puede mantener el comportamiento no bloqueante del código y también saber qué tarea ha finalizado y su índice en el vector sin ningún paso adicional de parámetros o búsqueda.

Comments are closed.