Multithreading: ¿Cuál es el punto de más hilos que núcleos?


142

Pensé que el objetivo de una computadora de múltiples núcleos es que podría ejecutar múltiples hilos simultáneamente. En ese caso, si tiene una máquina de cuatro núcleos, ¿qué sentido tiene tener más de 4 subprocesos funcionando a la vez? ¿No estarían simplemente robando tiempo (recursos de CPU) el uno del otro?


52
disfrutamos este tipo de preguntas, cuestionan lo fundamental de algo, que se da por sentado ...
sigan

66
¿Cuándo fue la última vez que tuvo Firefox, MS Word, Winamp, Eclipse y un administrador de descargas (más de cuatro programas / procesos) ejecutándose simultáneamente en su máquina de cuatro núcleos? Además, una sola aplicación a veces puede generar más de cuatro hilos, ¿qué tal eso?
Amarghosh

1
Robar no es necesariamente malo. Es posible que tenga un hilo con mayor prioridad para tareas importantes que necesitan robar tiempo.
kichik

1
@Amarghosh Supongo que esa era la pregunta, ¿por qué una sola aplicación puede querer generar más hilos que núcleos si no parece traer ningún beneficio de rendimiento? Y su ejemplo con más de cuatro programas no es muy relevante aquí. Como notó correctamente, esos son procesos. La función multitarea del sistema operativo (multiplexación de procesos) tiene muy poco que ver con los hilos dentro de un proceso.
Aleksandr Ivannikov

Respuestas:


81

La respuesta gira en torno al propósito de los hilos, que es el paralelismo: ejecutar varias líneas de ejecución separadas a la vez. En un sistema 'ideal', tendría que ejecutar un subproceso por núcleo: sin interrupción. En realidad este no es el caso. Incluso si tiene cuatro núcleos y cuatro subprocesos de trabajo, su proceso y sus subprocesos se cambiarán constantemente por otros procesos y subprocesos. Si está ejecutando un sistema operativo moderno, cada proceso tiene al menos un hilo, y muchos tienen más. Todos estos procesos se ejecutan a la vez. Probablemente tenga varios cientos de hilos ejecutándose en su máquina en este momento. Nunca tendrás una situación en la que se ejecute un hilo sin que te roben el tiempo. (Bueno, podría hacerlo si se está ejecutando en tiempo real, si está utilizando un sistema operativo en tiempo real o, incluso en Windows, utilice una prioridad de subproceso en tiempo real. Pero es raro).

Con eso como fondo, la respuesta: Sí, más de cuatro subprocesos en una verdadera máquina de cuatro núcleos pueden darle una situación en la que 'se roban el tiempo el uno al otro', pero solo si cada subproceso individual necesita 100% de CPU . Si un subproceso no funciona al 100% (como un subproceso de interfaz de usuario podría no estarlo, o un subproceso que realiza una pequeña cantidad de trabajo o espera en otra cosa), otro subproceso programado es en realidad una buena situación.

En realidad es más complicado que eso:

  • ¿Qué pasa si tiene cinco bits de trabajo que todos deben hacerse a la vez? Tiene más sentido ejecutarlos todos a la vez, que ejecutar cuatro de ellos y luego ejecutar el quinto más tarde.

  • Es raro que un hilo realmente necesite 100% de CPU. En el momento en que usa E / S de disco o red, por ejemplo, puede pasar tiempo esperando sin hacer nada útil. Esta es una situación muy común.

  • Si tiene un trabajo que debe ejecutarse, un mecanismo común es utilizar un conjunto de subprocesos. Puede tener sentido tener la misma cantidad de subprocesos que núcleos, pero el conjunto de subprocesos .Net tiene hasta 250 subprocesos disponibles por procesador . No estoy seguro de por qué hacen esto, pero supongo que tiene que ver con el tamaño de las tareas que se asignan para ejecutarse en los hilos.

Entonces: robar tiempo no es algo malo (y tampoco es realmente un robo: así es como se supone que funciona el sistema). Escriba sus programas multiproceso en función del tipo de trabajo que realizarán los hilos, que pueden no ser CPU -Unido. Calcule la cantidad de hilos que necesita según el perfil y la medición. Puede que le resulte más útil pensar en términos de tareas o trabajos, en lugar de hilos: escriba objetos de trabajo y déselos a un grupo para que se ejecuten. Finalmente, a menos que su programa sea realmente crítico para el rendimiento, no se preocupe demasiado :)


16
+1 para "pero solo si cada subproceso individual necesita 100% de CPU". Esa fue la suposición que no me di cuenta que estaba haciendo.
Nick Heiner

Una respuesta maravillosa a una gran pregunta. ¡Gracias!
Edgecase

53

El hecho de que exista un hilo no siempre significa que se esté ejecutando activamente. Muchas aplicaciones de subprocesos involucran algunos de los subprocesos que se van a dormir hasta que es hora de que hagan algo, por ejemplo, la entrada del usuario que desencadena los subprocesos para despertarse, hacer un procesamiento y volver a dormir.

Esencialmente, los subprocesos son tareas individuales que pueden operar independientemente uno del otro, sin necesidad de estar al tanto del progreso de otra tarea. Es bastante posible tener más de estos de los que tienes la capacidad de correr simultáneamente; siguen siendo útiles por conveniencia, incluso si a veces tienen que esperar en fila uno detrás del otro.


11
Bien dicho. El argumento 'un subproceso por CPU' solo se aplica al código enlazado a la CPU. La programación asincrónica es otra razón para usar hilos.
Joshua Davis

26

El punto es que, a pesar de no obtener una aceleración real cuando el recuento de subprocesos excede el recuento de núcleos, puede usar subprocesos para desenredar piezas de lógica que no deberían ser interdependientes.

Incluso en una aplicación moderadamente compleja, el uso de un solo hilo tratar de hacer todo rápidamente hace que el código fluya rápidamente. El hilo único pasa la mayor parte de su tiempo sondeando esto, verificando eso, llamando condicionalmente a las rutinas según sea necesario, y se vuelve difícil ver algo más que un montón de minucias.

Compare esto con el caso en el que puede dedicar hilos a tareas para que, mirando cualquier hilo individual, pueda ver lo que está haciendo ese hilo. Por ejemplo, un hilo puede bloquear la espera de entrada desde un socket, analizar la secuencia en mensajes, filtrar mensajes y, cuando aparece un mensaje válido, pasarlo a otro hilo de trabajo. El subproceso de trabajo puede funcionar en entradas de varias otras fuentes. El código para cada uno de estos exhibirá un flujo limpio y decidido, sin tener que hacer comprobaciones explícitas de que no hay nada más que hacer.

Particionar el trabajo de esta manera permite que su aplicación confíe en el sistema operativo para programar qué hacer a continuación con la CPU, por lo que no tiene que hacer verificaciones condicionales explícitas en todas partes de su aplicación sobre lo que podría bloquearse y lo que está listo para procesar.


1
Este es un pensamiento interesante ... Siempre había escuchado que el subproceso múltiple de una aplicación es una adición neta de complejidad, pero lo que estás diciendo tiene sentido.
Nick Heiner

El subprocesamiento múltiple de una aplicación agrega complejidad si sus preocupaciones no se separan adecuadamente. Si está diseñado con una superposición mínima de preocupaciones (y, por lo tanto, un estado compartido), es un ahorro neto en problemas de complejidad.
SOLO MI OPINIÓN correcta

Hay formas de estructurar aplicaciones de subproceso único para que el flujo de control sea más claro en el nivel en que escribe los programas. OTOH, si puede estructurar sus hilos para que solo se pasen mensajes entre sí (en lugar de compartir recursos), entonces es bastante simple resolver lo que está sucediendo y hacer que todo funcione.
Donal Fellows

1
Sin embargo, debería señalar que el uso de hilos solo puede simplificar las cosas hasta cierto punto. Con demasiada frecuencia se intenta hacer que dos subprocesos hagan el trabajo que uno debe hacer correctamente, en el que la complejidad regresa en picas. Los síntomas de esto son necesidades excesivas de comunicación y sincronización para coordinar algún resultado deseado.
JustJeff

15

Si un subproceso está esperando un recurso (como cargar un valor de RAM en un registro, E / S de disco, acceso a la red, iniciar un nuevo proceso, consultar una base de datos o esperar la entrada del usuario), el procesador puede trabajar en un subproceso diferente y volver al primer subproceso una vez que el recurso esté disponible. Esto reduce el tiempo que la CPU pasa inactiva, ya que la CPU puede realizar millones de operaciones en lugar de permanecer inactiva.

Considere un hilo que necesita leer datos de un disco duro. En 2014, un núcleo de procesador típico opera a 2.5 GHz y puede ejecutar 4 instrucciones por ciclo. Con un tiempo de ciclo de 0.4 ns, el procesador puede ejecutar 10 instrucciones por nanosegundo. Con tiempos de búsqueda típicos del disco duro mecánico de alrededor de 10 milisegundos, el procesador es capaz de ejecutar 100 millones de instrucciones en el tiempo que lleva leer un valor del disco duro. Puede haber mejoras significativas en el rendimiento con discos duros con un pequeño caché (4 MB de búfer) y unidades híbridas con unos pocos GB de almacenamiento, ya que la latencia de datos para lecturas secuenciales o lecturas de la sección híbrida puede ser varios órdenes de magnitud más rápido.

Un núcleo de procesador puede cambiar entre subprocesos (el costo de pausar y reanudar un subproceso es de alrededor de 100 ciclos de reloj) mientras que el primer subproceso espera una entrada de alta latencia (algo más costoso que los registros (1 reloj) y RAM (5 nanosegundos)) Estos incluyen E / S de disco, acceso a la red (latencia de 250 ms), lectura de datos de un CD o un bus lento, o una llamada a la base de datos. Tener más hilos que núcleos significa que se puede hacer un trabajo útil mientras se resuelven las tareas de alta latencia.

La CPU tiene un programador de subprocesos que asigna prioridad a cada subproceso y permite que un subproceso se suspenda y luego se reanude después de un tiempo predeterminado. El trabajo del planificador de subprocesos es reducir la agitación, lo que ocurriría si cada subproceso ejecutara solo 100 instrucciones antes de volver a suspenderlo. La sobrecarga de subprocesos de conmutación reduciría el rendimiento útil total del núcleo del procesador.

Por esta razón, es posible que desee dividir su problema en un número razonable de subprocesos. Si estaba escribiendo código para realizar la multiplicación de matrices, crear un subproceso por celda en la matriz de salida podría ser excesivo, mientras que un subproceso por fila o por n filas en la matriz de salida podría reducir el costo general de crear, pausar y reanudar subprocesos.

Por eso también es importante la predicción de rama. Si tiene una instrucción if que requiere cargar un valor desde RAM pero el cuerpo de las instrucciones if y else utilizan valores ya cargados en los registros, el procesador puede ejecutar una o ambas ramas antes de que se haya evaluado la condición. Una vez que la condición regrese, el procesador aplicará el resultado de la rama correspondiente y descartará la otra. Realizar un trabajo potencialmente inútil aquí es probablemente mejor que cambiar a un subproceso diferente, lo que podría provocar una paliza.

A medida que nos alejamos de los procesadores de un solo núcleo de alta velocidad de reloj a los procesadores de múltiples núcleos, el diseño del chip se ha centrado en agrupar más núcleos por dado, mejorar el intercambio de recursos en el chip entre los núcleos, mejores algoritmos de predicción de ramificaciones, mejor sobrecarga de conmutación de hilos, y mejor programación de hilos.


Sin embargo, lo mismo se puede hacer con un solo subproceso y una cola: \ ¿hay realmente algún beneficio en tener 80 subprocesos en 2-4 núcleos, en lugar de tener solo 2-4 núcleos que simplemente comen tareas fuera de la cola tan pronto como llegan? y no tienen nada que hacer?
Dmitry

8

La mayoría de las respuestas anteriores hablan sobre el rendimiento y la operación simultánea. Voy a abordar esto desde un ángulo diferente.

Tomemos el caso de, digamos, un programa de emulación de terminal simplista. Tienes que hacer lo siguiente:

  • Esté atento a los caracteres entrantes del sistema remoto y muéstrelos
  • Esté atento a las cosas que provienen del teclado y envíelas al sistema remoto

(Los emuladores de terminales reales hacen más, incluso pueden hacer eco de las cosas que escribe en la pantalla también, pero lo pasaremos por ahora).

Ahora el ciclo para leer desde el control remoto es simple, según el siguiente pseudocódigo:

while get-character-from-remote:
    print-to-screen character

El bucle para monitorear el teclado y enviar también es simple:

while get-character-from-keyboard:
    send-to-remote character

Sin embargo, el problema es que tienes que hacer esto simultáneamente. El código ahora debe verse más así si no tiene subprocesos:

loop:
    check-for-remote-character
    if remote-character-is-ready:
        print-to-screen character
    check-for-keyboard-entry
    if keyboard-is-ready:
        send-to-remote character

La lógica, incluso en este ejemplo deliberadamente simplificado que no tiene en cuenta la complejidad de las comunicaciones en el mundo real, es bastante confusa. Con el subprocesamiento, sin embargo, incluso en un solo núcleo, los dos bucles de pseudocódigo pueden existir independientemente sin entrelazar su lógica. Dado que ambos hilos estarán en su mayoría vinculados a E / S, no suponen una carga pesada para la CPU, a pesar de que, estrictamente hablando, desperdician más recursos de la CPU que el bucle integrado.

Ahora, por supuesto, el uso en el mundo real es más complicado que el anterior. Pero la complejidad del bucle integrado aumenta exponencialmente a medida que agrega más preocupaciones a la aplicación. La lógica se fragmenta cada vez más y debe comenzar a utilizar técnicas como máquinas de estado, corutinas, etc., para que las cosas sean manejables. Manejable, pero no legible. El enhebrado mantiene el código más legible.

Entonces, ¿por qué no usarías hilos?

Bueno, si sus tareas están vinculadas a la CPU en lugar de a las E / S, el subproceso en realidad ralentiza su sistema. El rendimiento sufrirá. Mucho, en muchos casos. ("Thrashing" es un problema común si suelta demasiados hilos enlazados a la CPU. Termina pasando más tiempo cambiando los hilos activos que ejecutando el contenido de los mismos hilos). Además, una de las razones por las que la lógica anterior es tan simple es que he elegido deliberadamente un ejemplo simplista (y poco realista). Si desea hacer eco de lo que se escribió en la pantalla, entonces tiene un nuevo mundo de dolor al introducir el bloqueo de los recursos compartidos. Con solo un recurso compartido, esto no es tanto un problema, pero comienza a convertirse en un problema cada vez mayor a medida que tiene más recursos para compartir.

Entonces, al final, el enhebrar es sobre muchas cosas. Por ejemplo, se trata de hacer que los procesos vinculados a E / S sean más receptivos (incluso si en general son menos eficientes) como algunos ya han dicho. También se trata de hacer que la lógica sea más fácil de seguir (pero solo si minimiza el estado compartido). Se trata de muchas cosas, y debe decidir si sus ventajas son mayores que sus desventajas caso por caso.


6

Aunque ciertamente puede usar hilos para acelerar los cálculos dependiendo de su hardware, uno de sus principales usos es hacer más de una cosa a la vez por razones de facilidad de uso.

Por ejemplo, si tiene que hacer un procesamiento en segundo plano y también responde a la entrada de la interfaz de usuario, puede usar hilos. Sin hilos, la interfaz de usuario se bloquea cada vez que intentas hacer un procesamiento pesado.

También vea esta pregunta relacionada: Usos prácticos para hilos


El manejo de UI es un ejemplo clásico de una tarea vinculada a IO. No es bueno tener un solo núcleo de CPU que realice tanto el procesamiento como las tareas de E / S.
Donal Fellows

6

Estoy totalmente en desacuerdo con la afirmación de @ kyoryu de que el número ideal es un hilo por CPU.

Piénselo de esta manera: ¿por qué tenemos sistemas operativos de procesamiento múltiple? Durante la mayor parte del historial de la computadora, casi todas las computadoras tenían una CPU. Sin embargo, a partir de la década de 1960, todas las computadoras "reales" tenían sistemas operativos de procesamiento múltiple (también conocido como multitarea).

Ejecutas múltiples programas para que uno pueda ejecutarse mientras que otros están bloqueados por cosas como IO.

Dejemos a un lado los argumentos sobre si las versiones de Windows anteriores a NT eran multitarea. Desde entonces, cada sistema operativo real tenía múltiples tareas. Algunos no lo exponen a los usuarios, pero está ahí de todos modos, haciendo cosas como escuchar la radio del teléfono celular, hablar con el chip GPS, aceptar la entrada del mouse, etc.

Los hilos son solo tareas que son un poco más eficientes. No hay una diferencia fundamental entre una tarea, proceso e hilo.

Una CPU es un desperdicio terrible, así que tenga muchas cosas listas para usar cuando pueda.

Estoy de acuerdo en que con la mayoría de los lenguajes de procedimiento, C, C ++, Java, etc., escribir un código seguro para subprocesos adecuado es mucho trabajo. Con 6 CPU centrales en el mercado hoy en día y 16 CPU centrales no muy lejos, espero que la gente se aleje de estos idiomas antiguos, ya que el subprocesamiento múltiple es un requisito cada vez más crítico.

El desacuerdo con @kyoryu es solo en mi humilde opinión, el resto es un hecho.


55
Si tiene muchos subprocesos vinculados al procesador , entonces el número ideal es uno por CPU (o quizás uno menos, para dejar uno para administrar todas las E / S y el sistema operativo y todas esas cosas). Si tiene hilos enlazados a IO , puede apilar bastante en una sola CPU. Las diferentes aplicaciones tienen diferentes combinaciones de tareas vinculadas al procesador y vinculadas a IO; eso es totalmente natural, pero por qué hay que tener cuidado con las declaraciones universales.
Donal Fellows

1
Por supuesto, la diferencia más importante entre subprocesos y procesos es que en Windows no hay fork (), por lo que la creación de procesos es realmente costosa, lo que lleva a un uso excesivo de subprocesos.
ninjalj

Excepto por el plegamiento de proteínas, SETI, etc., no hay tareas prácticas para el usuario que estén vinculadas a la computación por mucho tiempo. Siempre es necesario obtener información del usuario, hablar con el disco, hablar con el DBMS, etc. Sí, el gasto de fork () es una de las muchas cosas que Cutler maldijo a NT con lo que otros en DEC sabían.
fishtoprecords

5

Imagine un servidor web que tiene que atender un número arbitrario de solicitudes. Debe atender las solicitudes en paralelo porque, de lo contrario, cada nueva solicitud tiene que esperar hasta que se hayan completado todas las demás solicitudes (incluido el envío de la respuesta a través de Internet). En este caso, la mayoría de los servidores web tienen muchos menos núcleos que la cantidad de solicitudes que generalmente atienden.

También hace que sea más fácil para el desarrollador del servidor: solo tiene que escribir un programa de hilo que atienda una solicitud, no tiene que pensar en almacenar múltiples solicitudes, el orden en que las atiende, etc.


2
¿Está escribiendo software para un sistema operativo que admite subprocesos pero no tiene capacidad para multiplexar io? Creo que el servidor web es probablemente un mal ejemplo, ya que en este caso la multiplexación io casi siempre será más eficiente que generar más hilos que núcleos.
Jason Coco

3

Muchos hilos estarán dormidos, esperando la entrada del usuario, E / S y otros eventos.


Sin lugar a duda. solo use el Administrador de tareas en Windows o TOP en el sistema operativo real, y vea cuántas tareas / procesos hay. Siempre es 90% o más.
fishtoprecords

2

Los subprocesos pueden ayudar con la capacidad de respuesta en aplicaciones de IU. Además, puede usar hilos para obtener más trabajo de sus núcleos. Por ejemplo, en un solo núcleo, puede tener un hilo haciendo IO y otro haciendo algunos cálculos. Si fuera de un solo subproceso, el núcleo esencialmente podría estar inactivo esperando que se complete el IO. Ese es un ejemplo de alto nivel, pero los hilos definitivamente se pueden usar para golpear su CPU un poco más fuerte.


Más específicamente, un subproceso puede estar esperando E / S mientras que otro hace cómputo. Si la E / S tomara ciclos de CPU (significativos), no sería beneficioso ejecutarlo en un hilo separado. El beneficio es que su hilo de cómputo puede ejecutarse mientras su hilo de E / S gira sus pulgares esperando que un gran cilindro de aluminio gire en su lugar, o que los paquetes lleguen a Islandia desde el cable, o lo que sea.
Ken

2

Un procesador, o CPU, es el chip físico que está conectado al sistema. Un procesador puede tener múltiples núcleos (un núcleo es la parte del chip que es capaz de ejecutar instrucciones). Un núcleo puede aparecer en el sistema operativo como múltiples procesadores virtuales si es capaz de ejecutar simultáneamente múltiples subprocesos (un subproceso es una sola secuencia de instrucciones).

Un proceso es otro nombre para una aplicación. En general, los procesos son independientes entre sí. Si un proceso muere, no causa que otro proceso también muera. Los procesos pueden comunicarse o compartir recursos como memoria o E / S.

Cada proceso tiene un espacio de direcciones y una pila separados. Un proceso puede contener múltiples hilos, cada uno capaz de ejecutar instrucciones simultáneamente. Todos los hilos en un proceso comparten el mismo espacio de direcciones, pero cada hilo tendrá su propia pila.

Afortunadamente, con estas definiciones y más investigación utilizando estos fundamentos ayudará a su comprensión.


2
No veo cómo esto aborda su pregunta en absoluto. Mi interpretación de su pregunta es sobre el uso de hilos de núcleos y el uso óptimo de los recursos disponibles, o sobre el comportamiento de los hilos a medida que aumenta su número, o algo por el estilo de todos modos.
David

@David quizás no fue una respuesta directa a mi pregunta, pero todavía siento que aprendí al leerla.
Nick Heiner

1

El uso ideal de hilos es, de hecho, uno por núcleo.

Sin embargo, a menos que use exclusivamente IO asíncrono / sin bloqueo, existe una buena posibilidad de que tenga hilos bloqueados en IO en algún momento, lo que no usará su CPU.

Además, los lenguajes de programación típicos dificultan un poco el uso de 1 subproceso por CPU. Los lenguajes diseñados en torno a la concurrencia (como Erlang) pueden facilitar el uso de subprocesos adicionales.


El uso de subprocesos para tareas periódicas es un flujo de trabajo muy común y bienvenido, y sería mucho menos que ideal si robaran un núcleo.
Nick Bastin

@Nick Bastin: Sí, pero es más eficiente pegar esas tareas en una cola de tareas y ejecutarlas desde esa cola (o una estrategia similar). Para una eficiencia óptima, 1 hilo por núcleo supera a todos, ya que evita la sobrecarga de cambios innecesarios de contexto y la asignación de pilas adicionales. No importa qué, la tarea periódica debe robar un núcleo mientras está 'activa', ya que la CPU solo puede realizar una tarea por núcleo (además de cosas como hyperthreading si está disponible).
kyoryu

@Nick Bastin: Desafortunadamente, como dije en la respuesta principal, la mayoría de los lenguajes modernos no se prestan bien para implementar fácilmente un sistema que lo hace de manera efectiva no es trivial: terminas luchando contra el uso típico del lenguaje.
kyoryu

Mi punto no es que un hilo por núcleo no sea óptimo, es que un hilo por núcleo es un sueño imposible (a menos que esté incrustado) y diseñar para tratar de golpearlo es una pérdida de tiempo, por lo que también podría haga lo que lo hace fácil para usted (y de todos modos no es menos eficiente en un planificador moderno), en lugar de tratar de optimizar la cantidad de hilos que está utilizando. ¿Deberíamos girar los hilos sin una buena razón? Por supuesto que no, pero si está desperdiciando recursos informáticos innecesariamente es una preocupación, independientemente de los hilos.
Nick Bastin

@Nick Bastin: Entonces, para resumir, un hilo por núcleo es ideal, pero en realidad lograrlo no es muy probable. Probablemente debería haber sido más fuerte que 'algo difícil' al hablar sobre la probabilidad de lograr tal cosa.
kyoryu

1

La forma en que se diseñan algunas API, no tiene más remedio que ejecutarlas en un hilo separado (cualquier cosa con operaciones de bloqueo). Un ejemplo serían las bibliotecas HTTP de Python (AFAIK).

Por lo general, esto no es un gran problema (si es un problema, el sistema operativo o la API deben enviarse con un modo de operación asíncrono alternativo, es decir:) select(2), porque probablemente significa que el subproceso estará inactivo durante la espera de I / O finalización. Por otro lado, si algo está haciendo un cálculo pesada, que tiene que ponerlo en un hilo separado que, por ejemplo, el hilo de interfaz gráfica de usuario (a menos que disfrutar de multiplexación manual).


1

Sé que esta es una pregunta muy antigua con muchas buenas respuestas, pero estoy aquí para señalar algo que es importante en el entorno actual:

Si desea diseñar una aplicación para subprocesos múltiples, no debe diseñar para una configuración de hardware específica. La tecnología de la CPU ha avanzado bastante rápido durante años, y los recuentos de núcleos aumentan constantemente. Si diseña deliberadamente su aplicación de modo que use solo 4 hilos, entonces está potencialmente restringiéndose en un sistema octa-core (por ejemplo). Ahora, incluso los sistemas de 20 núcleos están disponibles comercialmente, por lo que tal diseño definitivamente está haciendo más daño que bien.


0

En respuesta a su primera conjetura: las máquinas multinúcleo pueden ejecutar simultáneamente múltiples procesos, no solo los múltiples hilos de un solo proceso.

En respuesta a su primera pregunta: el objetivo de varios subprocesos suele ser realizar simultáneamente múltiples tareas dentro de una aplicación. Los ejemplos clásicos en la red son un programa de correo electrónico que envía y recibe correo, y un servidor web que recibe y envía solicitudes de página. (Tenga en cuenta que es esencialmente imposible reducir un sistema como Windows para ejecutar solo un hilo o incluso un solo proceso. Ejecute el Administrador de tareas de Windows y normalmente verá una larga lista de procesos activos, muchos de los cuales ejecutarán múltiples hilos. )

En respuesta a su segunda pregunta: la mayoría de los procesos / subprocesos no están vinculados a la CPU (es decir, no se ejecutan de forma continua e ininterrumpida), sino que se detienen y esperan con frecuencia para que finalice la E / S. Durante esa espera, se pueden ejecutar otros procesos / subprocesos sin "robar" el código de espera (incluso en una máquina de núcleo único).


-5

Un hilo es una abstracción que le permite escribir código tan simple como una secuencia de operación, felizmente inconsciente de que el código se ejecuta entrelazado con otro código, o estacionado esperando IO, o (tal vez algo más consciente de) esperando el otro hilo eventos o mensajes.


Podría haber editado esto agregando más ejemplos desde los votos negativos, pero no se inventó un hilo (o proceso, en este contexto casi no hay diferencia) para escalar el rendimiento, sino para simplificar el código asincrónico y evitar escribir máquinas de estado complicadas que tuvo que manejar todos los superestados posibles en el programa. De hecho, generalmente había una CPU incluso en servidores grandes. Tengo curiosidad por qué mi respuesta se considera anti-útil.
KarlP

-8

El punto es que la gran mayoría de los programadores no entienden cómo diseñar una máquina de estados. Ser capaz de poner todo en su propio hilo libera al programador de tener que pensar en cómo representar eficientemente el estado de los diferentes cálculos en progreso para que puedan ser interrumpidos y luego reanudados.

Como ejemplo, considere la compresión de video, una tarea que requiere mucha CPU. Si está utilizando una herramienta de interfaz gráfica de usuario, probablemente desee que la interfaz siga siendo receptiva (muestre el progreso, responda a las solicitudes de cancelación, redimensione las ventanas, etc.). Por lo tanto, diseña el software del codificador para procesar una unidad grande (uno o más cuadros) a la vez y ejecutarlo en su propio hilo, separado de la interfaz de usuario.

Por supuesto, una vez que se da cuenta de que hubiera sido bueno poder guardar el estado de codificación en progreso para poder cerrar el programa para reiniciar o jugar un juego que consume muchos recursos, se da cuenta de que debería haber aprendido cómo diseñar máquinas de estado desde el comenzando. O eso, o decides diseñar un problema completamente nuevo de proceso de hibernación de tu sistema operativo para que puedas suspender y reanudar aplicaciones individuales en el disco ...


77
No (¡bastante!) Vale un -1, pero en serio, eso es lo más estúpidamente sarcástico que he escuchado a nadie decir sobre este tema. Yo, por ejemplo, no tengo problemas para implementar una máquina de estado. Ninguno en absoluto. Simplemente no me gusta usarlos cuando hay otras herramientas que dejan código más claro y más fácil de mantener . Las máquinas de estado tienen sus lugares, y en esos lugares no pueden ser igualados. Entrelazar operaciones intensivas de CPU con actualizaciones de GUI no es uno de esos lugares. Por lo menos, las corutinas son una mejor opción allí, y el enhebrado es aún mejor.
SOLO MI OPINIÓN correcta

Para todos los que modifiquen mi respuesta, ¡este NO es un argumento en contra del uso de hilos! Si puede codificar una máquina de estado que es genial, y seguro que a menudo tiene sentido ejecutar máquinas de estado en subprocesos separados, incluso si no tiene que hacerlo. Mi comentario fue que, a menudo, la elección de utilizar hilos se basa principalmente en el deseo de evitar el diseño de máquinas de estado, lo que muchos programadores consideran "demasiado difícil", en lugar de cualquier otro beneficio.
R .. GitHub DEJA DE AYUDAR AL HIELO
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.