Python Async del programador: simultaneidad basada en procesos
Página 1 de 3
El módulo asyncio puede ser el tema más candente en la ciudad, pero no es la única característica asíncrona que vale la pena conocer en Python. Aprenda sobre la concurrencia basada en procesos en este extracto de mi nuevo libro Programador Python: asíncrono Tiene la ventaja de no tener el problema GIL.
Programador Python:
asíncrono
Hilos, procesos, asyncio, etc.
Ahora disponible como libro impreso: Amazonas
Contenido
1) Recorrido relámpago de Python
Orígenes de Python, Python básico, estructuras de datos, estructuras de control: bucles, cuestiones espaciales, condiciones y sangrado, coincidencia de patrones, todo es un objeto: referencias, funciones, objetos y clases, herencia, núcleo y módulos, IDE para Python, Py Meta Filosofía, Dónde sigue, Resumen.
2) Se explica lo asincrónico
Hilo único, procesos, I/O-Bound y CPU-Bound, subprocesos, bloqueo, interbloqueo, proceso con múltiples subprocesos, asíncrono de subproceso único, eventos, eventos y subprocesos, Backback Hell, CPU múltiple: concurrencia, resumen.
3) Paralelismo básico desarrollado
Extracto 1: simultaneidad basada en procesos
Clase de proceso, Daemon, Esperar procesos, Esperar a que se complete el primero, Cómputo Pi, Fork v Spawn, Forkserve, Método de inicio de control, Resumen.
4) Cuerdas
Clase de subproceso, Subprocesos y GIL, Utilidades de subprocesos, Subprocesos de demonio, Utilidades de subprocesos, Subprocesos de demonio, Esperando un subproceso, Variables locales, Almacenamiento local de subprocesos, Subprocesos múltiples, Subprocesos vinculados a E/S, Suspensión (0), Objeto de temporizador, Resumen .
5) Candados y Candados
Condiciones de carrera, problema de hardware o Heisenbug, bloqueos, bloqueos y procesos, interbloqueo, bloqueos gestionados por contexto, bloqueo recursivo, semáforo, operaciones atómicas, Atomic CPython, código sin bloqueo, computación Pi usando bloqueos, resumen.
6) Sincronización
Unión , Primera meta , Eventos , Barrera , Objeto de estado , Objeto de estado universal , Resumen .
7) Intercambio de información
Cola, tuberías, colas para subprocesos, memoria compartida, tipos compartidos, memoria compartida sin procesar, memoria compartida, administrador, Compute Pi, resumen.
8) Grupo de procesos
Esperando procesos de grupo, cálculo de Pi usando AsyncResult, Map_async, Starmap_async, resultados inmediatos: imap, MapReduce, compartir y bloquear, resumen.
9) Gerentes de procesos
SyncManager, Cómo funcionan los proxies, Bloqueo, Cálculo de Pi con Manager, Administradores personalizados, Tipo de datos personalizado, BaseProxy, Proxy de propiedad, Administradores remotos, Llamada de procedimiento remoto, Pensamientos finales, Resumen.
10) Subprocesos
Ejecución de programas, E/S, Popen, Interacción, Conducto de lectura sin bloqueo, Uso de subprocesos, Resumen.
11) Futuros
Futuros, ejecutores, ejemplo de enlace de E/S, futuros en espera, devoluciones de llamada completadas en el futuro, manejo de excepciones, bloqueo y uso compartido de datos, bloqueo y parámetros de proceso, uso de un inicializador para crear globales compartidos, uso de un administrador de procesos para compartir recursos, intercambio de futuros y Interbloqueo, Computación con Futures Pi, Process Pool o Parallel Futures, Resumen.
12) Asyncio Básico
Callbacks, Futures and Waits, Coroutines, Waits, Sleep Waits, Tasks, Comando de Ejecución, Tasks and Futures, Waiting on Coroutines, Secuencial y Paralelo, Cancelación de Tareas, Manejo de Excepciones, Variables y Bloqueos Compartidos, Variables de Contexto, Agua.
13) Usando Asyncio
Subprocesos, carga de una página web, servidor, servidor web, servidor SSL, uso de subprocesos, conversión de bloqueo a no bloqueo, trabajo en subprocesos, por qué no solo usar subprocesos, tareas vinculadas a la CPU, módulos basados en Asyncio, bucles con otros eventos: Tkinter, Subprocesos, Resumen.
14) API de bajo nivel
Extracto 1: flujos y clientes web
Bucle de eventos, uso de un bucle, ejecución de tareas en procesos, cálculo de Pi con Asyncio, funciones de red,
Transportes y protocolos, servidor UDP, cliente UDP, transmisión UDP, sockets, implementación de bucle de eventos, características de una buena operación asincrónica, resumen.
Apéndice I Python en Visual Studio Code
La mayoría de los libros sobre programación asíncrona comienzan analizando los subprocesos, ya que generalmente se los considera los componentes básicos de la implementación. Sin embargo, existen ventajas al comenzar con los procesos de subproceso único predeterminados de Python. Las razones son tanto generales como específicas. Los procesos están aislados unos de otros, lo que hace que los interbloqueos sean un problema menor.
También está el hecho de que Python sufre de una limitación de gestión de subprocesos llamada Global Interpreter Lock, o GIL, que permite que solo un subproceso ejecute el sistema Python en un momento dado. Esto significa que múltiples subprocesos no pueden usar múltiples núcleos sin mucho esfuerzo y, por lo tanto, no proporciona una forma de acelerar las cosas. Hay más información sobre subprocesos y GIL en el próximo capítulo, pero por ahora debe saber que los procesos pueden acelerar su programa mediante el uso de múltiples núcleos. No puede obtener una verdadera concurrencia usando subprocesos de Python, pero puede usar procesos.
Lo que esto significa es que si tiene una tarea de E/S, el uso de subprocesos acelerará las cosas, porque cuando el subproceso de E/S se detiene, el procesador puede iniciar otro subproceso. Si tiene tareas vinculadas a la CPU, nada más ayudará que el paralelismo del proceso.
Clase de proceso
La idea básica al trabajar con procesos es que su programa Python inicial comience en su propio proceso, y puede usar la clase Process del módulo de multiprocesamiento para crear subprocesos. Un proceso hijo, en la terminología de Python, es creado y administrado por su proceso padre. Veamos el ejemplo más simple:
import multiprocessing def myProcess(): print("Hello Process World") if __name__ == '__main__': p1=multiprocessing.Process(target=myProcess) p1.start()
En este caso, todo lo que hacemos es crear un objeto de proceso cuyo objetivo se establece en el objeto de función myProcess. Llamar al método de inicio crea un nuevo proceso y comienza a ejecutar el código llamando a myProcess. Solo ve la pantalla Hello Process World.
Hay pocas cosas nuevas aquí, pero están sucediendo muchas cosas que no son obvias. Cuando llama al método de inicio, se crea un proceso completamente nuevo, completo con una nueva copia del intérprete de Python y el programa de Python. Exactamente cómo se presenta un programa de Python a un nuevo proceso depende del sistema en el que lo esté ejecutando, y ese es un punto delicado que se discutirá más adelante.
Por ahora, debe seguir tres reglas simples:
-
Utilice siempre if __name__ == ‘__main__’: para asegurarse de que el código de configuración no se ejecute en un proceso secundario.
-
No establezca ni modifique ningún recurso global en el código de configuración, ya que no siempre estará disponible en el proceso secundario.
-
Prefiere usar parámetros para pasar datos iniciales al proceso secundario en lugar de constantes globales.
Las razones de estas reglas se explican en detalle más adelante.
En general, para crear y ejecutar un nuevo proceso, crea un objeto de proceso usando:
class multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, daemon=None)
Puede ignorar el parámetro de grupo porque se incluye para que la llamada sea idéntica al parámetro que crea temas en el próximo capítulo. El destino es el invocable que desea que ejecute el nuevo proceso, y el nombre es el nombre aplicado al nuevo proceso. Si no proporciona un nombre, se crea un nombre único para usted. Los parámetros más importantes son args y kwargs, que especifican la posición y los parámetros de palabra clave para pasar al invocable.
Por ejemplo:
p1=multiprocessing.Process(target=myProcess,(42,43),
{“myParam1”:44})
llamará al objetivo así:
myProcess(42,43,myParam1=44)
Además del método de inicialización, el objeto Process tiene varios métodos y atributos útiles. Los más simples de estos son name y pid.
El atributo de nombre se puede utilizar para encontrar el nombre asignado del proceso secundario. No tiene mayor significado en el sentido de que el sistema operativo no sabe nada al respecto. El atributo pid, por otro lado, es el número de identificación del proceso asignado por el sistema operativo y es el pid que usa para tratar con procesos secundarios a través de comandos del sistema operativo como matar.
Tanto el atributo name como el pid ayudan a identificar el proceso, pero debe usar el atributo authkey por motivos de seguridad. Se establece en un número aleatorio cuando se carga el módulo de multiprocesamiento y está diseñado para actuar como un identificador seguro para los procesos secundarios. A cada objeto Process se le asigna el valor authkey del proceso principal, que se puede usar para probar que el proceso es de hecho un proceso secundario del padre, más sobre eso más adelante.
El módulo de multiprocesamiento también contiene algunos métodos que se pueden usar para aprender sobre el entorno en el que se ejecutan los procesos secundarios.
-
multiprocessing.cpu_count() devuelve el número de CPU, es decir, núcleos, en el sistema. Este es el número máximo teórico de procesos que pueden ejecutarse en paralelo. En la práctica, el número máximo disponible suele ser menor.
-
multiprocessing.cpu_set_executable() proporciona la ubicación del intérprete de Python para usar en los procesos secundarios.
Un proceso de Python no es el principal proceso nativo. El proceso principal tiene un intérprete de Python cargado con el código de Python especificado, listo para ejecutar la función pasada como destino.