Compatibilidad con la aceleración multiproceso y multihilo
Esta página describe hasta qué punto qiskit-addon-sqd admite la aceleración multihilo y multiproceso, así como los supuestos en los que puede basarse un desarrollador de computación de alto rendimiento (HPC) a la hora de integrar este paquete en una carga de trabajo acelerada.
La hipótesis de un solo hilo
Salvo que se indique lo contrario, las API de este paquete están pensadas para ser llamadas desde un único hilo. No se garantiza que las API de alto nivel que ofrece este paquete sean reentrantes, por lo que los usuarios finales no deben invocarlas desde ningún hilo que no sea el hilo principal.
Ejecución colectiva de múltiples procesos
Este paquete admite la aceleración colectiva multiproceso según el modelo «un solo programa, múltiples datos» (SPMD), en el que el programa completo se ejecuta como múltiples procesos aislados que funcionan con sincronización global explícita y comunicación entre ellos (por ejemplo, mpirun -n 128 python my_program.py). Dado que el estilo SPMD se integra perfectamente con los programadores de tareas y otro software paralelo, y es escalable a un gran número de procesos, es el modelo recomendado para cargas de trabajo de alto rendimiento y a gran escala, y es el tema central de esta página.
Aunque este paquete está diseñado para admitir diferentes backends de ejecución colectiva, su implementación actual está orientada a MPI, la API estándar de paso de mensajes para sistemas de HPC. Independientemente de cómo se implemente, este paquete da por hecho que cada proceso está controlado por un único hilo. En el caso del MPI, esto equivale a MPI_THREAD_FUNNELED o menos.
Si una función admite la ejecución colectiva, debe indicarse así en su documentación. Si la documentación no menciona la ejecución colectiva, la función no tiene semántica colectiva y debe invocarse únicamente desde el proceso de control.
El valor de retorno específico y la semántica de sincronización de una función colectiva se documentan junto con la propia función. En general, dicha documentación debería dejar claro:
- Si la función está pensada para que cada proceso la llame de forma independiente con sus propios datos locales, o para que la llamen de forma conjunta todos los procesos.
- Cómo deben coincidir sus argumentos entre los distintos procesos.
- Cómo se transmite su valor de retorno: si el resultado existe únicamente en el proceso de control, si todos los procesos reciben el mismo valor o si cada proceso recibe un identificador que hace referencia a una parte local de una estructura de datos distribuida.
Actualmente, solo hay una función que admite ser invocada de forma conjunta desde todos los procesos: diagonalize_fermionic_hamiltonian(). Cuando se invoca de forma colectiva, la fase del solucionador de valores propios es aquella en la que todos los procesos participan y aportan su trabajo, por lo que una implementación del solucionador de valores propios puede utilizar todos los procesos. Las partes restantes del bucle de recuperación de la configuración no tienen una implementación distribuida y se ejecutan únicamente en el proceso de control (rango 0).
En cambio, algunas implementaciones existentes de solucionadores de valores propios requieren que el programa que las invoca se ejecute fuera de un entorno MPI/SPMD, ya que inician y gestionan sus propios procesos paralelos de forma interna, por ejemplo, ejecutando mpirun en nombre del usuario. Este modo resulta práctico para el trabajo interactivo y con cuadernos de trabajo, y sigue siendo compatible; los requisitos que impone al programa que lo invoca se describen en la referencia de la API de la función diagonalize_fermionic_hamiltonian() .
Gestión de errores en un contexto multiproceso
Una función a la que se accede de forma conjunta desde todos los procesos no debe generar una excepción ni interrumpir solo un proceso, ya que eso dejaría a los procesos restantes en un punto muerto o en un estado incoherente. En cambio, la gestión de errores sigue la semántica «fail-stop» para el contexto de ejecución en su conjunto: ante un error, la implementación debe estar preparada para interrumpir de forma colectiva todo el contexto de ejecución (por ejemplo, utilizando MPI_Abort).
La API no puede garantizar la notificación coordinada de errores ni la transmisión colectiva de excepciones entre procesos, ya que las implementaciones de MPI no ofrecen tales garantías. Además, una implementación podría intentar hacer que un error sea visible para todos los procesos participantes —por ejemplo, haciendo que cada proceso genere una excepción—, pero esto solo se puede garantizar en la medida de lo posible y no se debe considerar como garantía de corrección o recuperación.
Se trata de características que una implementación colectiva puede tener, no de garantías sobre ninguna en concreto. En este paquete, el único paso colectivo es el solucionador de valores propios (véase la sección anterior); su implementación por defecto no es distribuida, por lo que estas consideraciones se aplican a un solucionador de valores propios colectivo personalizado proporcionado por el usuario.