Me temo que estoy "haciendo lo incorrecto" aquí, si es así, bórrame y me disculpo. En particular, no veo cómo creo las pequeñas anotaciones que algunas personas han creado. Sin embargo, tengo muchas preocupaciones / observaciones que hacer en este hilo.
1) El elemento comentado en el pseudocódigo en una de las respuestas populares
result = query( "select smurfs from some_mushroom" );
// twiddle fingers
go_do_something_with_result( result );
Es esencialmente falso. Si el hilo está computando, entonces no está girando los pulgares, está haciendo el trabajo necesario. Si, por otro lado, simplemente está esperando la finalización de IO, entonces es que no utiliza tiempo de CPU, el punto central de la infraestructura de control del hilo en el kernel es que la CPU se encuentra algo útil que hacer. La única forma de "girar los pulgares" como se sugiere aquí sería crear un bucle de sondeo, y nadie que haya codificado un servidor web real es lo suficientemente inepto como para hacerlo.
2) "Los hilos son difíciles", solo tiene sentido en el contexto del intercambio de datos. Si tiene subprocesos esencialmente independientes, como es el caso cuando se manejan solicitudes web independientes, entonces el subproceso es trivialmente simple, simplemente codifica el flujo lineal de cómo manejar un trabajo, y se sienta bien sabiendo que manejará múltiples solicitudes, y cada una Será efectivamente independiente. Personalmente, me aventuraría a que para la mayoría de los programadores, aprender el mecanismo de cierre / devolución de llamada es más complejo que simplemente codificar la versión de hilo de arriba a abajo. (Pero sí, si tiene que comunicarse entre los subprocesos, la vida se pone muy difícil muy rápido, pero no estoy convencido de que el mecanismo de cierre / devolución de llamada realmente cambie eso, solo restringe sus opciones, porque este enfoque aún se puede lograr con subprocesos De todos modos, eso '
3) Hasta ahora, nadie ha presentado ninguna evidencia real de por qué un tipo particular de cambio de contexto requeriría más o menos tiempo que cualquier otro tipo. Mi experiencia en la creación de núcleos multitarea (a pequeña escala para controladores integrados, nada tan sofisticado como un sistema operativo "real") sugiere que este no sería el caso.
4) Todas las ilustraciones que he visto hasta la fecha que pretenden mostrar qué tan rápido es Node que otros servidores web tienen fallas horribles, sin embargo, tienen fallas de una manera que ilustra indirectamente una ventaja que definitivamente aceptaría para Node (y de ninguna manera es insignificante). Nodo parece que no necesita (ni siquiera permite, en realidad) ajuste. Si tiene un modelo con subprocesos, debe crear suficientes subprocesos para manejar la carga esperada. Haz esto mal y terminarás con un bajo rendimiento. Si hay muy pocos subprocesos, entonces la CPU está inactiva, pero no puede aceptar más solicitudes, crea demasiados subprocesos y desperdiciará la memoria del kernel y, en el caso de un entorno Java, también desperdiciará la memoria principal del montón . Ahora, para Java, desperdiciar el montón es la primera y mejor manera de arruinar el rendimiento del sistema, porque la recolección eficiente de basura (actualmente, esto podría cambiar con G1, pero parece que el jurado todavía está fuera de ese punto a principios de 2013 al menos) depende de tener mucho montón de repuesto. Entonces, está el problema, sintonice con muy pocos subprocesos, tiene CPU inactivas y bajo rendimiento, sintonice con demasiados y se atasca de otras maneras.
5) Hay otra forma en la que acepto la lógica de la afirmación de que el enfoque de Node "es más rápido por diseño", y es esta. La mayoría de los modelos de subprocesos utilizan un modelo de cambio de contexto dividido en el tiempo, en capas sobre el modelo preventivo más apropiado (alerta de juicio de valor :) y más eficiente (no un juicio de valor). Esto sucede por dos razones, en primer lugar, la mayoría de los programadores no parecen entender la prioridad de prioridad, y en segundo lugar, si aprende a enhebrar en un entorno de Windows, la división de tiempo está allí, le guste o no (por supuesto, esto refuerza el primer punto ; en particular, las primeras versiones de Java utilizaron prioridad de prioridad en implementaciones de Solaris y división de tiempo en Windows. Debido a que la mayoría de los programadores no entendieron y se quejaron de que "el subproceso no funciona en Solaris" cambiaron el modelo a timeslice en todas partes). De todos modos, la conclusión es que la división de tiempo crea cambios de contexto adicionales (y potencialmente innecesarios). Cada cambio de contexto lleva tiempo de CPU, y ese tiempo se elimina efectivamente del trabajo que se puede hacer en el trabajo real en cuestión. Sin embargo, la cantidad de tiempo invertido en el cambio de contexto debido a la división de tiempo no debe ser más que un porcentaje muy pequeño del tiempo total, a menos que esté sucediendo algo bastante extraño, y no hay ninguna razón por la que pueda esperar que ese sea el caso en un servidor web simple). Entonces, sí, los cambios de contexto en exceso involucrados en la división de tiempo son ineficientes (y esto no sucede en y ese tiempo se elimina efectivamente del trabajo que se puede hacer en el trabajo real en cuestión. Sin embargo, la cantidad de tiempo invertido en el cambio de contexto debido a la división de tiempo no debe ser más que un porcentaje muy pequeño del tiempo total, a menos que esté sucediendo algo bastante extraño, y no hay ninguna razón por la que pueda esperar que ese sea el caso en un servidor web simple). Entonces, sí, los cambios de contexto en exceso involucrados en la división de tiempo son ineficientes (y esto no sucede en y ese tiempo se elimina efectivamente del trabajo que se puede hacer en el trabajo real en cuestión. Sin embargo, la cantidad de tiempo invertido en el cambio de contexto debido a la división de tiempo no debe ser más que un porcentaje muy pequeño del tiempo total, a menos que esté sucediendo algo bastante extraño, y no hay ninguna razón por la que pueda esperar que ese sea el caso en un servidor web simple). Entonces, sí, los cambios de contexto en exceso involucrados en la división de tiempo son ineficientes (y esto no sucede enhilos del kernel como regla, por cierto), pero la diferencia será un pequeño porcentaje del rendimiento, no el tipo de factores de números enteros que están implicados en las declaraciones de rendimiento que a menudo están implicadas para Node.
De todos modos, disculpas por que todo sea largo y divagante, pero realmente siento que hasta ahora, la discusión no ha demostrado nada, y me complacería saber de alguien en cualquiera de estas situaciones:
a) una explicación real de por qué Node debería ser mejor (más allá de los dos escenarios que he descrito anteriormente, el primero de los cuales (ajuste pobre) creo que es la explicación real de todas las pruebas que he visto hasta ahora. ], en realidad, cuanto más lo pienso, más me pregunto si la memoria utilizada por un gran número de pilas podría ser significativa aquí. Los tamaños de pila predeterminados para hilos modernos tienden a ser bastante grandes, pero la memoria asignada por un el sistema de eventos basado en el cierre sería solo lo que se necesita)
b) un punto de referencia real que realmente brinda una oportunidad justa al servidor de subprocesos elegido. Al menos de esa manera, tendría que dejar de creer que las afirmaciones son esencialmente falsas;> ([editar] eso es probablemente más fuerte de lo que pretendía, pero creo que las explicaciones dadas para los beneficios de rendimiento son incompletas en el mejor de los casos, y el los puntos de referencia mostrados no son razonables).
Saludos, Toby
select()
es más rápida que los intercambios de contexto de subprocesos.