¿Por qué es más caro crear un nuevo proceso en Windows que en Linux?

101

Escuché que crear un nuevo proceso en una caja de Windows es más caro que en Linux. ¿Es esto cierto? ¿Alguien puede explicar las razones técnicas de por qué es más caro y proporcionar alguna razón histórica para las decisiones de diseño detrás de esas razones?

Solo lectura
fuente

Respuestas:

68

mweerden: NT ha sido diseñado para múltiples usuarios desde el primer día, por lo que esta no es realmente una razón. Sin embargo, tiene razón en que la creación de procesos juega un papel menos importante en NT que en Unix ya que NT, a diferencia de Unix, favorece el multiproceso sobre el multiprocesamiento.

Rob, es cierto que fork es relativamente barato cuando se usa COW, pero de hecho, el fork es seguido principalmente por un ejecutivo. Y un ejecutivo también tiene que cargar todas las imágenes. Por lo tanto, discutir el rendimiento de la bifurcación es solo una parte de la verdad.

Cuando se habla de la velocidad de creación de procesos, probablemente sea una buena idea distinguir entre NT y Windows / Win32. En lo que respecta a NT (es decir, el núcleo en sí), no creo que la creación de procesos (NtCreateProcess) y la creación de subprocesos (NtCreateThread) sea significativamente más lenta que en el Unix promedio. Puede que haya un poco más en marcha, pero no veo la razón principal de la diferencia de rendimiento aquí.

Sin embargo, si observa Win32, notará que agrega bastante sobrecarga a la creación del proceso. Por un lado, requiere que se notifique al CSRSS sobre la creación del proceso, lo que implica LPC. Requiere que al menos kernel32 se cargue adicionalmente, y tiene que realizar una serie de elementos de trabajo de contabilidad adicionales antes de que el proceso se considere un proceso Win32 completo. Y no nos olvidemos de toda la sobrecarga adicional impuesta por el análisis de manifiestos, verificando si la imagen requiere una corrección de compatibilidad, verificando si se aplican las políticas de restricción de software, yada yada.

Dicho esto, veo la desaceleración general en la suma de todas esas pequeñas cosas que deben hacerse además de la creación sin procesar de un proceso, espacio VA y subproceso inicial. Pero como se dijo al principio, debido a que se privilegia el subproceso múltiple sobre la multitarea, el único software que se ve seriamente afectado por este gasto adicional es el software Unix mal adaptado. Aunque esta situación cambia cuando software como Chrome e IE8 redescubren repentinamente los beneficios del multiprocesamiento y comienzan a iniciar y desmontar procesos con frecuencia ...

Johannes Pasando
fuente
8
Fork no siempre va seguido de exec (), y la gente se preocupa solo por fork (). Apache 1.3 usa fork () (sin exec) en Linux y subprocesos en Windows, incluso si en muchos casos los procesos se bifurcan antes de ser necesarios y se mantienen en un grupo.
Blaisorblade
5
Sin olvidar, por supuesto, el comando 'vfork', que está diseñado para el escenario 'simplemente llamar al ejecutivo' que describe.
Chris Huang-Leaver
4
Otro tipo de software que se ve seriamente afectado por esto es cualquier tipo de scripting de shell que implique la coordinación de múltiples procesos. Bash scripting dentro de Cygwin, por ejemplo, sufre mucho por ello. Considere un bucle de shell que genera una gran cantidad de sed, awk y grep en las canalizaciones. Cada comando genera un proceso y cada tubería genera una subcapa y un nuevo proceso en esa subcapa. Unix fue diseñado con este tipo de uso en mente, razón por la cual la creación rápida de procesos sigue siendo la norma allí.
Dan Moulding
5
-1. La afirmación de que el software está "mal adaptado" porque no funciona bien en un sistema operativo mal diseñado y lleno de compatibilidad que ralentiza la creación de procesos es ridículo.
Miles Rout
6
@MilesRout el objetivo de la migración es modificar el software para que se ejecute en un nuevo sistema de destino, teniendo en cuenta las fortalezas y deficiencias de ese sistema. El software portado de bajo rendimiento es software portado deficientemente, independientemente de los obstáculos que proporcione el sistema operativo.
Dizzyspiral
28

Unix tiene una llamada al sistema 'fork' que 'divide' el proceso actual en dos y le da un segundo proceso que es idéntico al primero (módulo el retorno de la llamada fork). Dado que el espacio de direcciones del nuevo proceso ya está en funcionamiento, esto debería ser más barato que llamar a 'CreateProcess' en Windows y hacer que cargue la imagen exe, las DLL asociadas, etc.

En el caso de la bifurcación, el sistema operativo puede usar la semántica de 'copia en escritura' para las páginas de memoria asociadas con ambos procesos nuevos para garantizar que cada uno obtenga su propia copia de las páginas que posteriormente modifiquen.

Rob Walker
fuente
22
Este argumento solo es válido cuando realmente estás bifurcando. Si está iniciando un nuevo proceso, en Unix todavía tiene que bifurcar y ejecutar. Tanto Windows como Unix tienen copia en escritura. Sin duda, Windows reutilizará un EXE cargado si ejecuta una segunda copia de una aplicación. No creo que tu explicación sea correcta, lo siento.
Joel Spolsky
1
Más sobre exec () y fork () vipinkrsahu.blogspot.com/search/label/system%20programming
webkul
Agregué algunos datos de rendimiento en mi respuesta. stackoverflow.com/a/51396188/537980 Puede ver que es más rápido.
ctrl-alt-delor
25

Agregando a lo que dijo JP: la mayor parte de la sobrecarga pertenece al inicio de Win32 para el proceso.

El kernel de Windows NT es compatible con la bifurcación COW. SFU (entorno UNIX de Microsoft para Windows) los usa. Sin embargo, Win32 no es compatible con la bifurcación. Los procesos SFU no son procesos Win32. SFU es ortogonal a Win32: ambos son subsistemas de entorno construidos en el mismo kernel.

Además de las llamadas LPC fuera de proceso a CSRSS, en XP y posteriores hay una llamada fuera de proceso al motor de compatibilidad de aplicaciones para encontrar el programa en la base de datos de compatibilidad de aplicaciones. Este paso causa suficiente sobrecarga que Microsoft proporciona una opción de política de grupo para deshabilitar el motor de compatibilidad en WS2003 por razones de rendimiento.

Las bibliotecas de tiempo de ejecución de Win32 (kernel32.dll, etc.) también realizan muchas lecturas de registro e inicialización al inicio que no se aplican a UNIX, SFU o procesos nativos.

Los procesos nativos (sin subsistema de entorno) son muy rápidos de crear. SFU hace mucho menos que Win32 para la creación de procesos, por lo que sus procesos también son rápidos de crear.

ACTUALIZACIÓN PARA 2019: agregue LXSS: Subsistema de Windows para Linux

Reemplazo de SFU para Windows 10 es el subsistema de entorno LXSS. Es 100% modo kernel y no requiere nada de ese IPC que sigue teniendo Win32. Syscall para estos procesos se dirige directamente a lxss.sys / lxcore.sys, por lo que la bifurcación () u otro proceso de creación de llamadas solo cuesta 1 llamada al sistema para el creador, en total. [Un área de datos llamada instancia] realiza un seguimiento de todos los procesos, subprocesos y estado de tiempo de ejecución de LX.

Los procesos LXSS se basan en procesos nativos, no en procesos Win32. Todas las cosas específicas de Win32 como el motor de compatibilidad no están involucradas en absoluto.

Chris Smith
fuente
16

Además de la respuesta de Rob Walker: hoy en día tienes cosas como la biblioteca de subprocesos POSIX nativa, si quieres. Pero durante mucho tiempo, la única forma de "delegar" el trabajo en el mundo Unix fue usar fork () (y todavía se prefiere en muchas, muchas circunstancias). por ejemplo, algún tipo de servidor de socket

socket_accept ()
tenedor()
si (niño)
    handleRequest ()
más
    goOnBeingParent ()
Por lo tanto, la implementación de la bifurcación tenía que ser rápida y se han implementado muchas optimizaciones a lo largo del tiempo. Microsoft apoyó CreateThread o incluso fibras en lugar de crear nuevos procesos y el uso de la comunicación entre procesos. Creo que no es "justo" comparar CreateProcess con fork, ya que no son intercambiables. Probablemente sea más apropiado comparar fork / exec con CreateProcess.

VolkerK
fuente
2
Acerca de su último punto: fork () no es intercambiable con CreateProcess (), pero también se puede decir que Windows debería implementar fork () entonces, porque eso le da más flexibilidad.
Blaisorblade
Ah, el verbo To Bee.
acib708
Pero fork + exec en Linux es más rápido que CreateThread en MS-Windows. Y Linux puede bifurcar por sí solo para ser aún más rápido. Independientemente de cómo lo compare, la EM es más lenta.
ctrl-alt-delor
13

La clave de este asunto es el uso histórico de ambos sistemas, creo. Windows (y DOS antes de eso) han sido originalmente sistemas de un solo usuario para computadoras personales . Como tal, estos sistemas normalmente no tienen que crear muchos procesos todo el tiempo; En pocas palabras, un proceso solo se crea cuando este usuario solitario lo solicita (y los humanos no operamos muy rápido, relativamente hablando).

Los sistemas basados ​​en Unix han sido originalmente sistemas y servidores multiusuario. Especialmente para este último, no es raro tener procesos (por ejemplo, correo o demonios http) que dividen procesos para manejar trabajos específicos (por ejemplo, cuidando una conexión entrante). Un factor importante para hacer esto es el forkmétodo barato (que, como menciona Rob Walker ( 47865 ), inicialmente usa la misma memoria para el proceso recién creado) que es muy útil ya que el nuevo proceso tiene inmediatamente toda la información que necesita.

Está claro que, al menos históricamente, la necesidad de que los sistemas basados ​​en Unix tengan una creación rápida de procesos es mucho mayor que para los sistemas Windows. Creo que este sigue siendo el caso porque los sistemas basados ​​en Unix todavía están muy orientados a los procesos, mientras que Windows, debido a su historia, probablemente ha estado más orientado a los subprocesos (los subprocesos son útiles para crear aplicaciones receptivas).

Descargo de responsabilidad: de ninguna manera soy un experto en este asunto, así que perdóneme si me equivoqué.

mweerden
fuente
9

Parece que hay mucha justificación de "es mejor así".

Creo que la gente podría beneficiarse leyendo "Showstopper"; el libro sobre el desarrollo de Windows NT.

La razón principal por la que los servicios se ejecutan como DLL en un proceso en Windows NT es que son demasiado lentos como procesos separados.

Si se deprime y se ensucia, encontrará que la estrategia de carga de la biblioteca es el problema.

En Unices (en general), los segmentos de código de las bibliotecas compartidas (DLL) se comparten en realidad.

Windows NT carga una copia de la DLL por proceso, porque manipula el segmento de código de la biblioteca (y el segmento de código ejecutable) después de la carga. (¿Le dice dónde están sus datos?)

Esto da como resultado segmentos de código en bibliotecas que no son reutilizables.

Por lo tanto, el proceso de creación de NT es bastante caro. Y, en el lado negativo, hace que las DLL no guarden un ahorro apreciable en la memoria, sino una posibilidad de problemas de dependencia entre aplicaciones.

A veces vale la pena en ingeniería dar un paso atrás y decir, "ahora, si tuviéramos que diseñar esto para realmente apestar, ¿cómo se vería?"

Trabajé con un sistema integrado que alguna vez fue bastante temperamental, y un día lo miré y me di cuenta de que era un magnetrón de cavidad, con la electrónica en la cavidad de microondas. Lo hicimos mucho más estable (y menos parecido a un microondas) después de eso.

Tim Williscroft
fuente
3
Los segmentos de código son reutilizables siempre que la DLL se cargue en su dirección base preferida. Tradicionalmente, debe asegurarse de establecer direcciones base no conflictivas para todas las DLL que se cargarían en sus procesos, pero eso no funciona con ASLR.
Mike Dimmick
Hay alguna herramienta para reajustar todas las DLL, ¿no? No estoy seguro de lo que hace con ASLR.
Zan Lynx
3
El uso compartido de secciones de código también funciona en sistemas habilitados para ASLR.
Johannes Passing
@MikeDimmick para que todos, al hacer una DLL, tengan que cooperar para asegurarse de que no haya conflictos, ¿o los parchea a todos a nivel del sistema, antes de cargar?
ctrl-alt-delor
9

La respuesta corta es "capas y componentes de software".

La arquitectura de Windows SW tiene un par de capas y componentes adicionales que no existen en Unix o que están simplificados y manejados dentro del kernel en Unix.

En Unix, fork y exec son llamadas directas al kernel.

En Windows, la API del kernel no se usa directamente, hay win32 y algunos otros componentes encima, por lo que la creación del proceso debe pasar por capas adicionales y luego el nuevo proceso debe iniciarse o conectarse a esas capas y componentes.

Durante bastante tiempo, los investigadores y las corporaciones han intentado romper Unix de una manera vagamente similar, generalmente basando sus experimentos en el kernel de Mach ; un ejemplo bien conocido es OS X .. Sin embargo, cada vez que lo intentan, se vuelve tan lento que terminan fusionando al menos parcialmente las piezas en el núcleo, ya sea de forma permanente o para envíos de producción.

DigitalRoss
fuente
Las capas no necesariamente ralentizan las cosas: escribí un controlador de dispositivo, con muchas capas, en C. Código limpio, programación alfabetizada, fácil de leer. Era más rápido (marginalmente) que una versión escrita en ensamblador altamente optimizado, sin capas.
ctrl-alt-delor
La ironía es que NT es un kernel enorme (no un micro kernel)
ctrl-alt-delor
2

Como parece haber alguna justificación de MS-Windows en algunas de las respuestas, por ejemplo

  • “El kernel de NT y Win32 no son lo mismo. Si programa en el kernel de NT, entonces no es tan malo ”- Cierto, pero a menos que esté escribiendo un subsistema Posix, a quién le importa. Estarás escribiendo en win32.
  • “No es justo comparar la bifurcación con ProcessCreate, ya que hacen cosas diferentes y Windows no tiene bifurcación”. Es cierto, así que compararé lo similar con lo similar. Sin embargo, también compararé la bifurcación, porque tiene muchos casos de uso, como el aislamiento de procesos (por ejemplo, cada pestaña de un navegador web se ejecuta en un proceso diferente).

Ahora veamos los hechos, ¿cuál es la diferencia en el desempeño?

Datos resumidos de http://www.bitsnbites.eu/benchmarking-os-primitives/ .
Debido a que el sesgo es inevitable, al resumir, lo hice a favor del hardware de MS-Windows
para la mayoría de las pruebas i7 8 core 3.2GHz. Excepto Raspberry-Pi con Gnu / Linux

Una comparación de varias operaciones básicas, en Gnu / Linux, Apple-Mac y Windows de Microsoft (cuanto más pequeño, mejor)

Una comparación del proceso de creación de MS-Windows frente a Linux

Notas: En Linux, forkes más rápido que el método preferido de MS-Window CreateThread.

Números para operaciones de tipo de creación de procesos (porque es difícil ver el valor de Linux en el gráfico).

En orden de velocidad, de más rápido a más lento (los números son tiempo, lo pequeño es mejor).

  • Linux CreateThread 12
  • Mac CreateThread 15
  • Bifurcación de Linux 19
  • Windows CreateThread 25
  • Linux CreateProcess (fork + exec) 45
  • Mac Fork 105
  • Mac CreateProcess (fork + exec) 453
  • CreateProcess de Raspberry-Pi (fork + exec) 501
  • Windows CreateProcess 787
  • Windows CreateProcess con antivirus 2850
  • Windows Fork (simular con CreateProcess + fixup) mayor que 2850

Números para otras medidas

  • Creando un archivo.
    • Linux 13
    • Mac 113
    • Windows 225
    • Raspberry-Pi (con tarjeta SD lenta) 241
    • Windows con defensor y escáner de virus, etc. 12950
  • Asignar memoria
    • Linux 79
    • Windows 93
    • Mac 152
ctrl-alt-delor
fuente
1

Todo eso más está el hecho de que en la máquina Win lo más probable es que se active un software antivirus durante el CreateProcess ... Esa suele ser la mayor desaceleración.

Gabriel
fuente
1
Sí, es la mayor, pero no la única desaceleración significativa.
ctrl-alt-delor
1

También vale la pena señalar que el modelo de seguridad en Windows es mucho más complicado que en los sistemas operativos basados ​​en Unix, lo que agrega mucha sobrecarga durante la creación del proceso. Otra razón más por la que se prefiere el multiproceso al multiprocesamiento en Windows.

hacksoncode
fuente
1
Esperaría que un modelo de seguridad más complicado fuera más seguro; pero los hechos demuestran lo contrario.
Lie Ryan
4
SELinux también es un modelo de seguridad muy complejo, y no impone una sobrecarga significativa enfork()
Spudd86
6
@LieRyan, En diseño de software (en mi experiencia), más complicado rara vez significa más seguro.
Woodrow Douglass