Recientemente escuché a algunas personas decir que en Linux, casi siempre es mejor usar procesos en lugar de hilos, ya que Linux es muy eficiente en el manejo de procesos y porque hay tantos problemas (como el bloqueo) asociados con los hilos. Sin embargo, sospecho, porque parece que los hilos podrían dar una ganancia de rendimiento bastante grande en algunas situaciones.
Entonces, mi pregunta es, cuando me enfrento a una situación en la que los subprocesos y los procesos podrían manejarse bastante bien, ¿debería usar procesos o subprocesos? Por ejemplo, si estuviera escribiendo un servidor web, ¿debería usar procesos o hilos (o una combinación)?
linux
performance
multithreading
process
usuario17918
fuente
fuente
Respuestas:
Linux usa un modelo de subprocesos 1-1, con (para el núcleo) ninguna distinción entre procesos y subprocesos; todo es simplemente una tarea ejecutable. * *
En Linux, la llamada al sistema
clone
clona una tarea, con un nivel de uso compartido configurable, entre los cuales se encuentran:CLONE_FILES
: comparte la misma tabla de descriptores de archivo (en lugar de crear una copia)CLONE_PARENT
: no configure una relación padre-hijo entre la nueva tarea y la antigua (de lo contrario, childgetppid()
= parent'sgetpid()
)CLONE_VM
: comparte el mismo espacio de memoria (en lugar de crear una copia COW )fork()
llamadasclone(
menos compartidas)
ypthread_create()
llamadasclone(
más compartidas)
. ** **fork
ing cuesta un poquito más quepthread_create
ing debido a la copia de tablas y la creación de mapeos COW para la memoria, pero los desarrolladores del kernel de Linux han intentado (y han tenido éxito) minimizar estos costos.Cambiar entre tareas, si comparten el mismo espacio de memoria y varias tablas, será un poco más barato que si no se comparten, porque los datos ya pueden estar cargados en caché. Sin embargo, el cambio de tareas sigue siendo muy rápido, incluso si no se comparte nada; esto es algo más que los desarrolladores del kernel de Linux intentan garantizar (y logran garantizar).
De hecho, si está en un sistema multiprocesador, no compartir puede ser realmente beneficioso para el rendimiento: si cada tarea se ejecuta en un procesador diferente, la sincronización de la memoria compartida es costosa.
* Simplificado
CLONE_THREAD
hace que se comparta la entrega de señales (que necesitaCLONE_SIGHAND
, que comparte la tabla del controlador de señales).** Simplificado Existen tanto
SYS_fork
ySYS_clone
llamadas al sistema, pero en el núcleo, elsys_fork
ysys_clone
son ambos muy finas envolturas alrededor de la mismado_fork
función, que en sí es una envoltura delgada alrededorcopy_process
. Sí, los términosprocess
,thread
ytask
se usan indistintamente en el kernel de Linux ...fuente
socket
,bind
,listen
,fork
, y luego tener múltiples procesosaccept
conexiones en el mismo socket de escucha. Un proceso puede dejar de aceptar si está ocupado, y el kernel enrutará las conexiones entrantes a otro proceso (si nadie está escuchando, el kernel se pondrá en cola o caerá, dependiendo de lalisten
acumulación). No tienes mucho más control sobre la distribución del trabajo que eso, ¡pero generalmente eso es lo suficientemente bueno!clone()
determinar qué recursos se comparten. Una tarea también puedeunshare()
recursos en cualquier momento posterior.task_struct
para cada tarea. Esto a menudo se denomina "proceso" en todo el código del kernel, pero corresponde a cada subproceso ejecutable. No existeprocess_struct
; si un grupo detask_struct
s están vinculados por suthread_group
lista, entonces son el mismo "proceso" para el espacio de usuario. Hay un poco de manejo especial de "hilos", por ejemplo, todos los hilos hermanos se detienen en fork y exec, y solo aparece el hilo "principal"ls /proc
. Sin/proc/pid
embargo, se puede acceder a todos los hilos , ya sea que se enumeren/proc
o no.clone(CLONE_THREAD | CLONE_VM | CLONE_SIGHAND))
le daría un nuevo "hilo" que no comparte directorio de trabajo, archivos o bloqueos, mientras queclone(CLONE_FILES | CLONE_FS | CLONE_IO)
le daría un "proceso" que sí lo hace. El sistema subyacente crea tareas mediante la clonación;fork()
ypthread_create()
son solo funciones de biblioteca que invocan de maneraclone()
diferente (como escribí en esta respuesta).Linux (y de hecho Unix) le ofrece una tercera opción.
Opción 1 - procesos
Cree un ejecutable independiente que maneje una parte (o todas las partes) de su aplicación e invoque por separado para cada proceso, por ejemplo, el programa ejecuta copias de sí mismo para delegar tareas.
Opción 2 - hilos
Cree un ejecutable independiente que se inicie con un solo subproceso y cree subprocesos adicionales para realizar algunas tareas.
Opción 3 - tenedor
Solo disponible bajo Linux / Unix, esto es un poco diferente. Un proceso bifurcado realmente es su propio proceso con su propio espacio de direcciones: no hay nada que el niño pueda hacer (normalmente) para afectar el espacio de direcciones de sus padres o hermanos (a diferencia de un hilo), por lo que obtendrá mayor robustez.
Sin embargo, las páginas de memoria no se copian, son de copia en escritura, por lo que generalmente se usa menos memoria de la que pueda imaginar.
Considere un programa de servidor web que consta de dos pasos:
Si usó hilos, el paso 1 se haría una vez, y el paso 2 en varios hilos. Si utilizó procesos "tradicionales", los pasos 1 y 2 tendrían que repetirse para cada proceso, y la memoria para almacenar la configuración y los datos de tiempo de ejecución duplicados. Si usó fork (), puede hacer el paso 1 una vez y luego fork (), dejando los datos de tiempo de ejecución y la configuración en la memoria, intactos, no copiados.
Entonces hay realmente tres opciones.
fuente
Eso depende de muchos factores. Los procesos son más pesados que los subprocesos y tienen un mayor costo de inicio y cierre. La comunicación entre procesos (IPC) también es más difícil y lenta que la comunicación entre hilos.
Por el contrario, los procesos son más seguros y seguros que los subprocesos, porque cada proceso se ejecuta en su propio espacio de direcciones virtuales. Si un proceso falla o tiene un desbordamiento del búfer, no afecta a ningún otro proceso en absoluto, mientras que si un subproceso se bloquea, elimina todos los otros subprocesos en el proceso, y si un subproceso tiene un desbordamiento del búfer, se abre Un agujero de seguridad en todos los hilos.
Por lo tanto, si los módulos de su aplicación pueden ejecutarse principalmente de forma independiente con poca comunicación, probablemente debería usar procesos si puede pagar los costos de inicio y cierre. El impacto de rendimiento de IPC será mínimo y estará un poco más seguro contra errores y agujeros de seguridad. Si necesita todo el rendimiento que puede obtener o tener muchos datos compartidos (como estructuras de datos complejas), use hilos.
fuente
Otros han discutido las consideraciones.
Quizás la diferencia importante es que en Windows los procesos son pesados y caros en comparación con los subprocesos, y en Linux la diferencia es mucho menor, por lo que la ecuación se equilibra en un punto diferente.
fuente
Había una vez un Unix y en este viejo y bueno Unix había mucha sobrecarga para los procesos, por lo que lo que hicieron algunas personas inteligentes fue crear hilos, que compartirían el mismo espacio de direcciones con el proceso padre y solo necesitaban un contexto reducido cambiar, lo que haría que el cambio de contexto sea más eficiente.
En un Linux contemporáneo (2.6.x) no hay mucha diferencia en el rendimiento entre un cambio de contexto de un proceso en comparación con un hilo (solo el material MMU es adicional para el hilo). Existe el problema con el espacio de direcciones compartido, lo que significa que un puntero defectuoso en un hilo puede dañar la memoria del proceso principal u otro hilo dentro del mismo espacio de direcciones.
Un proceso está protegido por la MMU, por lo que un puntero defectuoso causará una señal 11 y no habrá corrupción.
En general, usaría procesos (no mucha sobrecarga de cambio de contexto en Linux, pero protección de memoria debido a MMU), pero pthreads si necesitara una clase de planificador en tiempo real, que es una taza de té diferente en conjunto.
¿Por qué crees que los hilos tienen una ganancia de rendimiento tan grande en Linux? ¿Tienes algún dato para esto, o es solo un mito?
fuente
¿Qué tan estrechamente acopladas están tus tareas?
Si pueden vivir independientemente el uno del otro, entonces use procesos. Si dependen el uno del otro, entonces use hilos. De esa manera puede matar y reiniciar un proceso incorrecto sin interferir con el funcionamiento de las otras tareas.
fuente
Para complicar aún más las cosas, existe el almacenamiento local de subprocesos y la memoria compartida de Unix.
El almacenamiento local de subprocesos permite que cada subproceso tenga una instancia separada de objetos globales. La única vez que lo usé fue cuando construí un entorno de emulación en linux / windows, para el código de aplicación que se ejecutó en un RTOS. En el RTOS, cada tarea era un proceso con su propio espacio de direcciones, en el entorno de emulación, cada tarea era un hilo (con un espacio de direcciones compartido). Al usar TLS para cosas como singletons, pudimos tener una instancia separada para cada hilo, al igual que en el entorno RTOS 'real'.
La memoria compartida puede (obviamente) brindarle los beneficios de rendimiento de tener múltiples procesos que acceden a la misma memoria, pero con el costo / riesgo de tener que sincronizar los procesos correctamente. Una forma de hacerlo es hacer que un proceso cree una estructura de datos en la memoria compartida y luego envíe un identificador a esa estructura a través de la comunicación tradicional entre procesos (como una tubería con nombre).
fuente
En mi trabajo reciente con LINUX, una cosa a tener en cuenta son las bibliotecas. Si está utilizando subprocesos, asegúrese de que las bibliotecas que pueda usar en todos los subprocesos sean seguras para subprocesos. Esto me quemó un par de veces. Notablemente libxml2 no es seguro para subprocesos fuera de la caja. Se puede compilar con subprocesos seguros, pero eso no es lo que obtienes con aptitude install.
fuente
Tendría que estar de acuerdo con lo que has estado escuchando. Cuando comparamos nuestro clúster (
xhpl
y demás), siempre obtenemos un rendimiento significativamente mejor con los procesos a través de subprocesos.</anecdote>
fuente
La decisión entre hilo / proceso depende un poco de para qué la usará. Uno de los beneficios de un proceso es que tiene un PID y puede eliminarse sin terminar también con el padre.
Para un ejemplo del mundo real de un servidor web, apache 1.3 solía soportar solo múltiples procesos, pero en 2.0 agregaron una abstracción para que pueda alternar entre ambos. Los comentarios parecen estar de acuerdo en que los procesos son más robustos, pero los subprocesos pueden ofrecer un rendimiento un poco mejor (excepto en las ventanas donde el rendimiento de los procesos apesta y solo desea usar subprocesos).
fuente
Para la mayoría de los casos, preferiría procesos sobre hilos. los subprocesos pueden ser útiles cuando tiene una tarea relativamente más pequeña (sobrecarga del proceso >> tiempo empleado por cada unidad de tarea dividida) y existe la necesidad de compartir la memoria entre ellos. Piensa en una gran variedad. Además (fuera del tema), tenga en cuenta que si la utilización de su CPU es del 100 por ciento o cercana, no habrá ningún beneficio con el procesamiento o subprocesamiento múltiple. (de hecho empeorará)
fuente
Subprocesos -> Los subprocesos comparten un espacio de memoria, es una abstracción de la CPU, es liviano. Procesos -> Los procesos tienen su propio espacio de memoria, es una abstracción de una computadora. Para paralelizar la tarea, necesita abstraer una CPU. Sin embargo, las ventajas de usar un proceso sobre un hilo son la seguridad, la estabilidad, mientras que un hilo usa menos memoria que el proceso y ofrece una menor latencia. Un ejemplo en términos de web sería Chrome y Firefox. En el caso de Chrome, cada pestaña es un proceso nuevo, por lo tanto, el uso de memoria de Chrome es mayor que el de Firefox, mientras que la seguridad y la estabilidad proporcionadas son mejores que las de Firefox. La seguridad aquí proporcionada por Chrome es mejor, ya que cada pestaña es un proceso nuevo. Una pestaña diferente no puede espiar en el espacio de memoria de un proceso dado.
fuente
Creo que todos han hecho un gran trabajo respondiendo a su pregunta. Solo estoy agregando más información sobre hilo versus proceso en Linux para aclarar y resumir algunas de las respuestas anteriores en el contexto del núcleo. Entonces, mi respuesta es con respecto al código específico del kernel en Linux. De acuerdo con la documentación del kernel de Linux, no existe una distinción clara entre el hilo y el proceso, excepto que el hilo usa un espacio de direcciones virtuales compartido a diferencia del proceso. También tenga en cuenta que el Kernel de Linux utiliza el término "tarea" para referirse al proceso y al hilo en general.
"No hay estructuras internas que implementen procesos o subprocesos, en su lugar hay una estructura task_struct que describe una unidad de programación abstracta llamada tarea"
Además, según Linus Torvalds, NO debe pensar en el proceso versus el hilo en absoluto y porque es demasiado limitante y la única diferencia es COE o Contexto de ejecución en términos de "separar el espacio de direcciones del padre" o el espacio de direcciones compartido. De hecho, usa un ejemplo de servidor web para hacer su punto aquí (que recomiendo leer).
Crédito completo a la documentación del kernel de Linux
fuente
Si necesita compartir recursos, realmente debería usar hilos.
Considere también el hecho de que los cambios de contexto entre subprocesos son mucho menos costosos que los cambios de contexto entre procesos.
No veo ninguna razón para ir explícitamente con procesos separados a menos que tenga una buena razón para hacerlo (seguridad, pruebas de rendimiento comprobadas, etc.)
fuente