Las características de Erlang
De Erlang Programming (2009):
La concurrencia de Erlang es rápida y escalable. Sus procesos son livianos, ya que la máquina virtual Erlang no crea un subproceso de sistema operativo para cada proceso creado. Se crean, programan y manejan en la VM, independientemente del sistema operativo subyacente. Como resultado, el tiempo de creación del proceso es del orden de microsegundos e independiente del número de procesos concurrentes existentes. Compare esto con Java y C #, donde para cada proceso se crea un subproceso subyacente del sistema operativo: obtendrá algunas comparaciones muy competitivas, con Erlang superando en gran medida ambos idiomas.
De la programación orientada a la concurrencia en Erlang (pdf) (diapositivas) (2003):
Observamos que el tiempo necesario para crear un proceso Erlang es constante de 1 µs hasta 2.500 procesos; a partir de entonces aumenta a aproximadamente 3 µs para hasta 30,000 procesos. El rendimiento de Java y C # se muestra en la parte superior de la figura. Para un pequeño número de procesos, se necesitan unos 300 µs para crear un proceso. Crear más de dos mil procesos es imposible.
Vemos que para hasta 30,000 procesos, el tiempo para enviar un mensaje entre dos procesos Erlang es de aproximadamente 0.8 µs. Para C #, se necesitan aproximadamente 50 µs por mensaje, hasta el número máximo de procesos (que fue aproximadamente 1800 procesos). Java fue aún peor, para hasta 100 procesos, tardó aproximadamente 50 µs por mensaje a partir de entonces aumentó rápidamente a 10 ms por mensaje cuando hubo aproximadamente 1000 procesos Java.
Mis pensamientos
Técnicamente, no entiendo completamente por qué los procesos de Erlang son mucho más eficientes para generar nuevos procesos y tienen huellas de memoria mucho más pequeñas por proceso. Tanto el sistema operativo como la máquina virtual Erlang tienen que hacer programación, cambios de contexto y realizar un seguimiento de los valores en los registros, etc.
Simplemente, ¿por qué los hilos del sistema operativo no se implementan de la misma manera que los procesos en Erlang? ¿Tienen que apoyar algo más? ¿Y por qué necesitan una mayor huella de memoria? ¿Y por qué tienen un desove y una comunicación más lentos?
Técnicamente, ¿por qué los procesos en Erlang son más eficientes que los hilos del sistema operativo cuando se trata de desove y comunicación? ¿Y por qué no se pueden implementar y administrar subprocesos en el sistema operativo de la misma manera eficiente? ¿Y por qué los subprocesos del sistema operativo tienen una mayor huella de memoria, además de una reproducción y comunicación más lenta?
erl +P 1000100 +hms 100
y luego escriba{_, PIDs} = timer:tc(lists,map,[fun(_)->spawn(fun()->receive stop -> ok end end) end, lists:seq(1,1000000)]).
y espere unos tres minutos para obtener el resultado. Eso es muy simple. Se necesitan 140us por proceso y 1GB de RAM completa en la computadora portátil mía. Pero es directamente de shell, debería ser mejor a partir del código compilado.Respuestas:
Hay varios factores contribuyentes:
fuente
Después de más investigación encontré una presentación de Joe Armstrong.
De Erlang - software para un mundo concurrente (presentación) (a los 13 min):
Creo que responde, si no todas, al menos algunas de mis preguntas
fuente
Implementé corutinas en ensamblador y medí el rendimiento.
El cambio entre corutinas, también conocido como procesos Erlang, requiere aproximadamente 16 instrucciones y 20 nanosegundos en un procesador moderno. Además, a menudo conoce el proceso al que está cambiando (ejemplo: un proceso que recibe un mensaje en su cola puede implementarse como transferencia directa del proceso de llamada al proceso de recepción) para que el programador no entre en juego, lo que hace que Es una operación O (1).
Para cambiar los subprocesos del sistema operativo, se necesitan entre 500 y 1000 nanosegundos, ya que está llamando al núcleo. El programador de subprocesos del sistema operativo puede ejecutarse en tiempo O (log (n)) u O (log (log (n))), lo que comenzará a ser notable si tiene decenas de miles, o incluso millones de subprocesos.
Por lo tanto, los procesos de Erlang son más rápidos y escalan mejor porque tanto la operación fundamental de la conmutación es más rápida como el programador se ejecuta con menos frecuencia.
fuente
Los procesos de Erlang corresponden (aproximadamente) a hilos verdes en otros idiomas; no hay separación forzada por el sistema operativo entre los procesos. (Puede haber una separación forzada por el idioma, pero esa es una protección menor a pesar de que Erlang hace un mejor trabajo que la mayoría). Debido a que son mucho más livianos, se pueden usar mucho más ampliamente.
Los subprocesos del sistema operativo, por otro lado, pueden programarse simplemente en diferentes núcleos de CPU y (en su mayoría) pueden admitir procesamiento independiente vinculado a la CPU. Los procesos del sistema operativo son como subprocesos del sistema operativo, pero con una separación mucho más fuerte impuesta por el sistema operativo. El precio de estas capacidades es que los subprocesos del sistema operativo y (aún más) los procesos son más caros.
Otra forma de entender la diferencia es esta. Suponiendo que iba a escribir una implementación de Erlang encima de la JVM (no es una sugerencia particularmente loca), entonces haría que cada proceso de Erlang sea un objeto con algún estado. Luego tendría un grupo de instancias de Thread (generalmente dimensionadas de acuerdo con el número de núcleos en su sistema host; ese es un parámetro ajustable en tiempos de ejecución reales de Erlang, por cierto) que ejecutan los procesos de Erlang. A su vez, eso distribuirá el trabajo que se realizará entre los recursos reales del sistema disponibles. Es una forma bastante ordenada de hacer las cosas, pero se basa por completosobre el hecho de que cada proceso individual de Erlang no hace mucho. Eso está bien, por supuesto; Erlang está estructurado para no requerir que esos procesos individuales sean pesados, ya que es el conjunto general de ellos el que ejecuta el programa.
En muchos sentidos, el verdadero problema es uno de terminología. Las cosas que Erlang llama procesos (y que corresponden fuertemente al mismo concepto en CSP, CCS, y particularmente el cálculo π) simplemente no son las mismas cosas que los lenguajes con herencia C (incluyendo C ++, Java, C # y muchos otros) llaman un proceso o un hilo. Hay algunas similitudes (todas implican alguna noción de ejecución concurrente) pero definitivamente no hay equivalencia. Así que tenga cuidado cuando alguien le diga "proceso"; podrían entender que significa algo completamente diferente ...
fuente
Creo que Jonas quería algunos números al comparar los hilos del sistema operativo con los procesos de Erlang. El autor de Programming Erlang, Joe Armstrong, hace un tiempo probó la escalabilidad de la generación de procesos de Erlang en subprocesos del sistema operativo. Escribió un servidor web simple en Erlang y lo probó contra Apache multiproceso (ya que Apache usa hilos del sistema operativo). Hay un sitio web antiguo con datos que datan de 1998. Solo he logrado encontrar ese sitio exactamente una vez. Entonces no puedo proporcionar un enlace. Pero la información está ahí afuera. El punto principal del estudio mostró que Apache alcanzó un máximo de 8K procesos, mientras que su servidor Erlang escrito a mano manejó más de 10K procesos.
fuente
Debido a que el intérprete de Erlang solo tiene que preocuparse por sí mismo, el sistema operativo tiene muchas otras cosas de las que preocuparse.
fuente
Una de las razones es que el proceso erlang no se crea en el sistema operativo, sino en evm (máquina virtual erlang), por lo que el costo es menor.
fuente