Estaba leyendo la descripción de los dos del documento de Python :
Aparecer
El proceso principal inicia un nuevo proceso de interpretación de python. El proceso secundario solo heredará los recursos necesarios para ejecutar el método run() de los objetos del proceso. En particular, los identificadores y descriptores de archivo innecesarios del proceso principal no se heredarán. Iniciar un proceso con este método es bastante lento en comparación con el uso de fork o forkserver. [Disponible en Unix y Windows. El predeterminado en Windows y macOS.]
tenedor
El proceso principal usa os.fork() para bifurcar el intérprete de Python. El proceso hijo, cuando comienza, es efectivamente idéntico al proceso padre. Todos los recursos del padre son heredados por el proceso hijo. Tenga en cuenta que la bifurcación segura de un proceso de subprocesos múltiples es problemática. [Disponible solo en Unix. El valor predeterminado en Unix.]
Y mi pregunta es:
- ¿Es que la bifurcación es mucho más rápida porque no intenta identificar qué recursos copiar?
Sí, es mucho más rápido. El kernel puede clonar todo el proceso y solo copia las páginas de memoria modificadas como un todo . No es necesario canalizar recursos a un nuevo proceso y arrancar el intérprete desde cero.
- ¿Es que, dado que la bifurcación duplica todo, "desperdiciaría" muchos más recursos en comparación con spawn ()?
La bifurcación en los núcleos modernos solo "copia sobre escritura" y solo afecta las páginas de memoria que realmente cambian. La advertencia es que "escribir" ya abarca simplemente iterar sobre un objeto en CPython. Eso es porque el número de referencias del objeto se incrementa.
Si tiene procesos de ejecución prolongada con muchos objetos pequeños en uso, esto puede significar que desperdicia más memoria que con la generación. Como anécdota, recuerdo que Facebook afirmó haber reducido considerablemente el uso de la memoria al cambiar de "fork" a "spawn" para sus procesos de Python.
Hay una compensación entre 3 métodos de inicio de multiprocesamiento :
fork es más rápido porque hace una copia en escritura de toda la memoria virtual del proceso principal, incluido el intérprete de Python inicializado, los módulos cargados y los objetos construidos en la memoria.
Pero la bifurcación no copia los subprocesos del proceso principal. Por lo tanto, los bloqueos (en la memoria) que en el proceso principal estaban en manos de otros subprocesos se atascan en el hijo sin subprocesos propios para desbloquearlos, listos para causar un punto muerto cuando el código intenta adquirir alguno de ellos. Además, cualquier biblioteca nativa con subprocesos bifurcados estará en un estado roto.
Los módulos y objetos de Python copiados pueden ser útiles o pueden inflar innecesariamente cada proceso secundario bifurcado.
El proceso secundario también "hereda" recursos del sistema operativo, como descriptores de archivos abiertos y puertos de red abiertos. Esos también pueden generar problemas, pero Python soluciona algunos de ellos.
Entonces , la bifurcación es rápida, insegura y tal vez inflada.
Sin embargo, estos problemas de seguridad pueden no causar problemas dependiendo de lo que haga el proceso hijo.
spawn inicia un proceso secundario de Python desde cero sin la memoria del proceso principal, los descriptores de archivo, los subprocesos, etc. cargue el módulo de destino y ejecute el destino invocable.
Entonces , spawn es seguro, compacto y más lento, ya que Python tiene que cargar, inicializarse, leer archivos, cargar e inicializar módulos, etc.
Sin embargo, es posible que no sea notablemente más lento en comparación con el trabajo que realiza el proceso secundario.
forkserver bifurca un duplicado del proceso de Python actual que se reduce a aproximadamente un proceso de Python nuevo. Esto se convierte en el proceso de "servidor de bifurcación". Luego, cada vez que inicia un proceso secundario, le pide al servidor de bifurcación que bifurque a un niño y ejecute su objetivo invocable.
Todos esos procesos secundarios comienzan siendo compactos y sin bloqueos atascados.
forkserver es más complicado y no está bien documentado. La publicación de blog de Bojan Nikolic explica más sobre forkserver y su método secreto set_forkserver_preload()
para precargar algunos módulos. Tenga cuidado con el uso de un método no documentado, esp. antes de la corrección de errores en Python 3.7.0 .
Entonces , forkserver es rápido, compacto y seguro, pero es más complicado y no está bien documentado .
[Los documentos no son muy buenos en todo esto, así que combiné información de varias fuentes e hice algunas inferencias. Comente cualquier error.]