tag - ¿Por qué crear un nuevo proceso es más caro en Windows que en Linux?
tag folders (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 se simplifican y manejan dentro del kernel en Unix.
En Unix, fork y exec son llamadas directas al kernel.
En Windows, la API 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 dividir Unix de una manera vagamente similar, generalmente basando sus experimentos en el núcleo 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 kernel, ya sea permanentemente o para envíos de producción.
Escuché que crear un nuevo proceso en una caja de Windows es más costoso que en Linux. ¿Es esto cierto? ¿Alguien puede explicar los motivos técnicos de por qué es más costoso y proporcionar razones históricas para las decisiones de diseño detrás de esas razones?
Además de la respuesta de Rob Walker: Nowadys tiene cosas como Native POSIX Thread Library, si lo desea. Pero durante mucho tiempo, la única forma de "delegar" el trabajo en el mundo de Unix fue usar fork () (y aún así es preferible en muchas, muchas circunstancias). por ejemplo, algún tipo de servidor de socket
socket_accept() fork() if (child) handleRequest() else goOnBeingParent() Por lo tanto, la implementación de la horquilla tuvo que ser rápida y se implementaron muchas optimizaciones a lo largo del tiempo. Microsoft aprobó 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.
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 realmente admite COW tenedor. SFU (entorno UNIX de Microsoft para Windows) los usa. Sin embargo, Win32 no es compatible con fork. 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 provoca una sobrecarga suficiente que Microsoft proporciona una opción de directiva de grupo para deshabilitar el motor de compatibilidad en WS2003 por motivos de rendimiento.
Las bibliotecas de tiempo de ejecución de Win32 (kernel32.dll, etc.) también realizan muchas lecturas de registro e inicialización en el 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.
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 generalmente no tienen que crear muchos procesos todo el tiempo; En pocas palabras, un proceso solo se crea cuando este solo usuario lo solicita (y los humanos no operamos muy rápido, en términos relativos).
Los sistemas basados en Unix han sido originalmente sistemas y servidores multiusuario. Especialmente para este último, no es raro tener procesos (p. Ej., Daemons de correo o http) que dividan los procesos para gestionar trabajos específicos (por ejemplo, cuidar una conexión entrante). Un factor importante para hacer esto es el método de fork
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 de inmediato 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 de procesos rápida es mucho mayor que la de los sistemas de Windows. Creo que este es todavía el caso porque los sistemas basados en Unix todavía están muy orientados al proceso, mientras que Windows, debido a su historial, probablemente ha estado más orientado a los subprocesos (los subprocesos son útiles para hacer aplicaciones receptivas).
Descargo de responsabilidad: de ninguna manera soy un experto en este asunto, así que perdónenme si me equivoqué.
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 una gran cantidad de gastos generales durante la creación del proceso. Otra razón más por la que se prefiere el subprocesamiento múltiple al procesamiento múltiple en Windows.
Todo eso además es el hecho de que en la máquina de Win probablemente un software antivirus se activará durante el CreateProcess ... Esa suele ser la mayor ralentización.
Uh, parece que hay una gran cantidad de justificación "es mejor así".
Creo que las personas podrían beneficiarse leyendo "Showstopper"; el libro sobre el desarrollo de Windows NT.
La razón por la que los servicios se ejecutan como DLL en un proceso en Windows NT es que eran demasiado lentos como procesos separados.
Si se ensucia 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 realmente.
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.
Entonces, el proceso de NT creado es bastante caro. Y en el lado negativo, hace que el DLL no guarde un ahorro apreciable en la memoria, sino una posibilidad de problemas de dependencia entre aplicaciones.
A veces vale la pena invertir en ingeniería para dar un paso atrás y decir: "ahora, si fuéramos a diseñar esto para realmente apestar, ¿qué aspecto tendría?"
Trabajé con un sistema embebido que era bastante temperamental una vez, 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 como un microondas) después de eso.
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 a la horquilla). Dado que el espacio de direcciones del nuevo proceso ya está en funcionamiento, esto debería ser más económico que llamar a ''CreateProcess'' en Windows y hacer que cargue la imagen exe, dlls asociados, etc.
En el caso de la horquilla, el sistema operativo puede usar la semántica de "copiar sobre 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 modifique.
mweerden: NT ha sido diseñado para usuarios múltiples desde el primer día, por lo que esta no es realmente una razón. Sin embargo, tiene razón acerca de 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 multihilo sobre el multiprocesamiento.
Rob, es cierto que el tenedor es relativamente barato cuando se usa COW, pero de hecho, tenedor es seguido principalmente por un ejecutivo. Y un ejecutivo tiene que cargar todas las imágenes también. Discutir el rendimiento del tenedor, por lo tanto, es solo una parte de la verdad.
Al analizar la velocidad de creación del proceso, probablemente sea una buena idea distinguir entre NT y Windows / Win32. En cuanto a NT (es decir, el kernel 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 haber un poco más de cosas sucediendo, pero no veo la razón principal para la diferencia de rendimiento aquí.
Sin embargo, si observa Win32, notará que agrega bastante sobrecarga para procesar la creación. Por un lado, requiere que se notifique al CSRSS sobre la creación del proceso, que involucra a LPC. Requiere al menos que Kernel32 se cargue adicionalmente, y debe realizar una serie de elementos de trabajo de contabilidad adicionales para que se realice antes de que el proceso se considere como un proceso de Win32 completo. Y no nos olvidemos de toda la sobrecarga adicional impuesta por los manifiestos de análisis, verificando si la imagen requiere un ajuste 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 cruda de un proceso, espacio VA e hilo inicial. Pero como se dijo al principio, debido a que se favorece el multihilo sobre la multitarea, el único software que se ve seriamente afectado por este gasto adicional es el software Unix mal portado. Aunque esta situación cambia cuando software como Chrome e IE8 redescubren repentinamente los beneficios del multiprocesamiento y comienzan a iniciar y desmontar con frecuencia los procesos ...