La Red de Conocimientos Pedagógicos - Currículum vitae - El uso de subprocesos múltiples en MPI

El uso de subprocesos múltiples en MPI

En el artículo anterior presentamos las operaciones de memoria compartida en MPI-3. A continuación, presentaremos el uso de subprocesos múltiples en MPI para ayudarnos a comprender la seguridad de subprocesos introducida en MPI-3. se presentará en el próximo artículo).

Por lo general, la entidad básica para la mayoría de las operaciones en MPI es un proceso, pero se pueden ejecutar varios subprocesos en un proceso MPI.

El proceso es la unidad básica de ejecución dinámica del sistema operativo. En el sistema operativo tradicional, el proceso es tanto la unidad de asignación básica como la unidad de ejecución básica. Por lo general, puede haber varios subprocesos en un proceso y hay al menos un subproceso en un proceso. Los subprocesos pueden hacer uso de los recursos que pertenecen a los procesos. En los sistemas operativos que introducen subprocesos, los procesos generalmente se utilizan como unidad básica para asignar recursos y los subprocesos se utilizan como unidades básicas para la ejecución y la programación independientes, ya que los subprocesos tienen una granularidad menor que la de los procesos. Básicamente, no posee recursos del sistema, por lo que la sobrecarga de su programación será mucho menor y puede aumentar de manera más eficiente el grado de ejecución simultánea entre múltiples programas en el sistema.

La principal diferencia entre procesos y subprocesos es que son diferentes formas de gestionar los recursos del sistema operativo. Los procesos tienen espacios de direcciones independientes y los subprocesos son simplemente rutas de ejecución diferentes en un proceso. Los subprocesos tienen su propia pila y variables locales, pero no tienen espacios de direcciones independientes.

Se pueden ejecutar varios subprocesos en un proceso MPI, y varios subprocesos del mismo proceso tienen las mismas oportunidades de participar en la comunicación MPI del proceso.

En algunos casos, el uso de subprocesos múltiples en MPI puede proporcionar una gran comodidad, como por ejemplo:

En el caso de un solo subproceso, un proceso no puede ejecutar de forma segura su propio punto de bloqueo. comunicaciones punto a punto. Al utilizar subprocesos múltiples, dos subprocesos del mismo proceso pueden bloquear el envío y el bloqueo de la recepción respectivamente sin interbloqueo.

MPI requiere que las llamadas MPI_Init y MPI_Finalize estén emparejadas y ejecutadas en el mismo hilo. El hilo que realiza estas dos operaciones se llama hilo principal (la llamada MPI_Finalize del hilo principal debe ser). ejecutado en todos los demás subprocesos. Ejecutado después de realizar comunicación relacionada con MPI, E/S y otras operaciones MPI.

La seguridad de subprocesos significa que varios subprocesos pueden realizar llamadas relacionadas para pasar mensajes al mismo tiempo sin afectarse entre sí.

MPI está diseñado para ser seguro para subprocesos, pero la aplicación en sí es responsable de mantener la seguridad de subprocesos múltiples. Una forma sencilla es utilizar diferentes subobjetos de comunicación en diferentes subprocesos, de modo que las operaciones entre subprocesos puedan realizarse. no interferir entre sí. La mayoría de las operaciones de MPI cumplen con las condiciones de seguridad de subprocesos, pero existen excepciones, por ejemplo, el uso de MPI.Comm.Probe o MPI.Comm.Iprobe en subprocesos múltiples para determinar el origen y el tamaño de un mensaje, y luego la operación de. recibir el mensaje No es seguro para subprocesos, pero MPI-3 proporciona versiones seguras para subprocesos MPI.Comm.Mprobe y MPI.Comm.Improbe, que se presentarán en el próximo artículo. Además, MPI.File.Seek no es seguro para subprocesos, pero su operación puede ser reemplazada por funciones de operación de archivos de compensación explícitas seguras para subprocesos, como MPI.File.Read_at.

Esta función es responsable de inicializar el entorno de ejecución multiproceso MPI además de implementar la inicialización normal realizada por MPI.Init. El parámetro requerido indica el nivel requerido de soporte de subprocesos múltiples. Los valores posibles son los siguientes:

Estas constantes son todas números enteros y varían numéricamente de pequeño a grande.

Esta función devuelve el nivel de subprocesos múltiples realmente admitido por el entorno MPI.

Diferentes procesos en MPI.COMM_WORLD pueden establecer diferentes niveles de soporte de subprocesos respectivamente. El efecto real de llamar a MPI.Init en MPI multiproceso es equivalente a llamar a MPI.Init_thread con MPI.THREAD_SINGLE.

Nota: Cuando se utiliza mpi4py, MPI.Init y MPI.Init_thread se llamarán automáticamente al importar MPI desde el paquete mpi4py, por lo que generalmente no es necesario llamarlos explícitamente en el programa. El nivel de subproceso requerido predeterminado de MPI.Init_thread en mpi4py es MPI.THREAD_MULTIPLE, pero el nivel de subproceso real obtenido lo proporciona el entorno MPI. Si desea controlar manualmente la inicialización del programa MPI o establecer el nivel del subproceso MPI, puede importar el módulo rc antes de importar MPI y configurar rc.initialize = False, y luego inicializarlo manualmente o configurar rc.thread_level en el requerido. nivel ("múltiple", "serializado", "canalizado" o "único").

Devuelve los niveles de subprocesos admitidos por el entorno MPI.

Determine si el hilo que llama a esta función es el hilo principal. Si es así, devuelva True; de ​​lo contrario, devuelva False.

MPI no proporciona funciones ni métodos para crear subprocesos. La creación de subprocesos debe realizarse mediante otras herramientas. Esto garantiza que los programas MPI puedan utilizar cualquier subproceso que sea compatible con la implementación de MPI y no esté limitado a un determinado. hilo. Las herramientas de subprocesos más utilizadas incluyen la biblioteca Pthreads y la biblioteca OpenMP.

En Python, puede usar el módulo de subprocesos (llamado _thread en Python 3), pero el más comúnmente usado es el módulo de subprocesos de nivel superior, más fácil de usar, construido sobre él. La siguiente es una breve introducción al módulo de subprocesos.

El módulo threading proporciona varias funciones y objetos. Aquí presentamos principalmente el objeto threading.Thread. Este objeto representa una actividad de subproceso que se ejecuta por separado. Puede crear y ejecutar un subproceso separado de dos maneras: pasarle un objeto que pueda llamarse o heredar esta clase y sobrecargar el método run(); Generalmente, en las subclases solo se pueden sobrecargar los métodos __init__() y run(), y no se deben sobrecargar otros métodos.

Cuando se crea un hilo, se debe iniciar utilizando el método start(), que llama internamente al método run().

Después de que se inicia un subproceso, su estado será "activo" hasta que el método run() del subproceso se detenga (ya sea que finalice normalmente o anormalmente). Puede utilizar el método is_alive() para comprobar si el hilo está "vivo".

Otros subprocesos pueden llamar al método join() de un subproceso, que bloqueará el subproceso que llama hasta que el subproceso llamado se detenga.

Cada hilo tiene un nombre. Si no se establece, el sistema le asignará un nombre predeterminado. Puede pasar un nombre específico a un hilo al construirlo o cambiarlo dinámicamente durante el tiempo de ejecución a través del atributo de nombre.

Un hilo se puede marcar como un hilo de demonio, y el hilo de demonio puede ejecutarse para siempre sin bloquear la salida del programa principal. El uso de subprocesos de demonio es útil para un servicio que no tiene una manera fácil de interrumpir subprocesos, o donde desea que un subproceso termine en medio de su trabajo sin perder ni corromper datos. Puede marcar un hilo como un hilo de demonio configurando el atributo de demonio del hilo. De forma predeterminada, los subprocesos no se utilizan como subprocesos de demonio.

El hilo inicial del programa es el hilo principal, y el hilo principal no es un hilo de demonio.

Inicializar un objetivo de hilo.

El grupo debe establecerse inicialmente en Ninguno, que actualmente no tiene ningún efecto y está reservado para una futura expansión. El objetivo es un objeto invocable. Si el nombre no es Ninguno, establezca el nombre del hilo. El nombre predeterminado es "Thread-N". N es un número, args y kwargs son otros parámetros.

Si una subclase quiere anular este constructor, primero debe llamar al constructor de la clase base (Thread.__init__()) y luego hacer otras cosas.

Inicia este hilo. Un hilo solo puede llamar a este método como máximo una vez; de lo contrario, se generará una excepción RuntimeError.

La actividad o trabajo de un hilo. Este método se puede anular en subclases para completar el trabajo requerido.

Espera a que el hilo se detenga. De forma predeterminada, el subproceso que llama a este método se bloqueará indefinidamente hasta que el subproceso llamado se detenga, pero si el parámetro de tiempo de espera se establece en un número de coma flotante, solo esperará segundos de tiempo de espera antes de regresar, independientemente de si el subproceso llamado finalizó. Este método siempre devuelve Ninguno, por lo que se debe llamar al método is_alive() para determinar si el retorno de la llamada se debe a que el hilo llamado se detuvo o a que se esperó el tiempo de espera.

El método join() de un hilo se puede llamar varias veces.

Devuelve si el hilo está "vivo".

El nombre del hilo, que es una cadena.

El identificador del hilo, que es un número entero distinto de cero.

La mitad del valor booleano indica si el hilo es un hilo de demonio.

A continuación se ofrecen ejemplos de uso.

Los resultados de la ejecución son los siguientes:

Lo anterior presenta el uso de subprocesos múltiples en MPI. En el próximo artículo, presentaremos Mprobe seguro para subprocesos en MPI-3. .