2010-01-03 17 views
14

No tengo mucha experiencia con temas como Concurrencia y Multithreading. De hecho, en la mayor parte de mi carrera de desarrollo web nunca había necesitado tocar estos temas.Concurrencia y multiprocesamiento

Siento que es un concepto importante, especialmente para aplicaciones de escritorio y básicamente cualquier otra aplicación que no genere HTML :).

Después de leer un poco sobre concurrencia, parece ser mejor soportado en idiomas como Go (google programming language) y no entiendo por qué un lenguaje sería mejor que otros en un concepto como concurrence, ya Básicamente se trata de poder bifurcar() procesos y calcular cosas en paralelo, ¿verdad? ¿No es así como funciona la programación?

El subprocesamiento múltiple parece ser una rama de la concurrencia, ya que le permite ejecutar cosas en paralelo bajo el mismo proceso, aunque parece ser específico de la plataforma de cómo se implementa.

Creo que mi pregunta es, ¿por qué lenguajes específicos ser mejor en concurrencia que otros y por qué iba horquilla() Ing procesos sean una mejor solución en vez de utilizar hilos?

+0

nitpick - Go no es "lengua de programación de Google". Es un lenguaje que inventaron algunos de sus empleados, pero lo último que supe es que Google aún no lo usa internamente. –

+0

Dice "Google programming language", pero en cualquier caso no veo nada de malo en referirme a un lenguaje desarrollado y promocionado por Google como "Google's". – danben

Respuesta

28

Bueno, por un lado, los hilos múltiples no son lo mismo que los procesos múltiples, por lo que fork() realmente no se aplica aquí.

El procesamiento multiproceso/paralelo es difícil. Primero debes averiguar cómo dividir realmente la tarea que se va a realizar. Luego, debe coordinar todos los bits paralelos, que pueden necesitar comunicarse entre sí o compartir recursos. Luego debe consolidar los resultados, que en algunos casos pueden ser tan difíciles como los dos pasos anteriores. Me estoy simplificando aquí, pero espero que entiendas la idea.

Así que su pregunta es, ¿por qué algunos idiomas serían mejores en eso? Bueno, varias cosas pueden hacerlo más fácil:

  • Estructuras de datos inmutables optimizadas. Desea adherirse a estructuras inmutables siempre que sea posible en el procesamiento paralelo, porque son mucho más fáciles de razonar. Algunos lenguajes tienen un mejor soporte para estos, y algunos tienen varias optimizaciones, es decir, la capacidad de empalmar colecciones sin ninguna copia real mientras se sigue imponiendo la inmutabilidad. Siempre puede construir sus propias estructuras como estas, pero es más fácil si el lenguaje o marco lo hace por usted.

  • Primitivas de sincronización y facilidad de uso. Cuando diferentes subprocesos comparten estado, deben estar sincronizados y hay muchas maneras diferentes de lograr esto. Mientras más amplia sea la matriz de primitivas de sincronización que obtienes, más fácil será tu tarea en última instancia. El rendimiento tendrá éxito si tiene que sincronizar con una sección crítica en lugar de un bloqueo de lector-escritor.

  • Transacciones atómicas. Incluso mejor que una amplia gama de primitivas de sincronización no es tener que usarlas en absoluto. Los motores de base de datos son muy buenos en esto; en lugar de usted, el programador, teniendo que averiguar exactamente qué recursos necesita bloquear y cuándo y cómo, simplemente le dice al compilador o al intérprete, "todas las cosas debajo de esta línea deben suceder juntas, así que asegúrese de que nadie más lío con eso mientras lo estoy usando ". Y el motor descubrirá el bloqueo por ti. Casi nunca se obtiene este tipo de simplicidad en un lenguaje de programación abstracto, pero cuanto más cerca se puede llegar, mejor. Los objetos a prueba de hilos que combinan múltiples operaciones comunes en uno son un comienzo.

  • Paralelismo automático. Digamos que tienes que iterar a través de una larga lista de elementos y transformarlos de alguna manera, como multiplicar 50,000 matrices de 10x10. ¿No sería bueno si pudieras decirle al compilador: Oye, cada operación se puede hacer de forma independiente, así que utiliza un núcleo de CPU separado para cada uno? ¿Sin tener que implementar realmente el enhebrado usted mismo? Algunos idiomas admiten este tipo de cosas; por ejemplo, el equipo .NET ha estado trabajando en PLINQ.

Estos son solo algunos ejemplos de cosas que pueden hacer su vida más fácil en aplicaciones paralelas/de subprocesos múltiples. Estoy seguro de que hay muchos más.

+3

+1. Los lenguajes libres de efectos secundarios también facilitan las cosas (como los funcionales, como Haskell). – LBushkin

1

Re: por qué algunos idiomas son mejores para la concurrencia que otros: todo depende de las herramientas que el lenguaje ofrece al programador. Algunos lenguajes, como C++, le dan acceso de bajo nivel a los hilos del sistema. Java tiene todo tipo de bibliotecas que ofrecen construcciones para programación concurrente, como patrones de diseño (ver pestillo, barrera, etc.). Algunos lenguajes hacen que sea más fácil que otros tratar con hilos. Algunos idiomas evitan que se comparta estado entre hilos, que es una fuente importante de errores.

Y luego, algunos idiomas tienen diferentes modelos de hilos subyacentes que otros. El modelo de subprocesos de Python, como yo lo entiendo, usa una sola cadena de sistema y maneja todo el cambio de contexto en sí mismo, que no es tan limpio como lo es solo como granular como una sola instrucción de Python.

Como analogía, es como preguntar por qué algunos lenguajes son mejores para manejar expresiones regulares, o buscar, o hacer cálculos matemáticos complejos cuando al final todo se está moviendo.

Editar: frunsi es correcto, los hilos de Python son hilos del sistema (aparentemente esta es una idea falsa común). El problema al que me refería era con el GIL, o bloqueo de intérprete global, que controla la ejecución de subprocesos. Solo se puede ejecutar un único subproceso en el intérprete de Python de una vez, y el contexto solo cambia entre las instrucciones. Mi conocimiento del multihilo de Python proviene principalmente de este documento: www.dabeaz.com/python/GIL.pdf. Tal vez un poco fuera del tema, pero una buena referencia, no obstante.

+0

El comentario sobre python es incorrecto, ¿tal vez estabas pensando en algún tipo de subprocesos ligeros? Ellos tienen un intento diferente. Ver http://docs.python.org/library/thread.html#module-thread. Aunque hay (o hubo) un problema con un bloqueo de intérprete global en Python, pero su afirmación es claramente incorrecta. – Frunsi

0

ningún idioma es mejor que otro, se trata de los conceptos. Hacer cosas simultáneamente por procesos consume generalmente más recursos que hilos (que podrían verse como procesos livianos), algunos lenguajes vienen con facilidad también usan libs. Los subprocesos de Java son fáciles de usar, los subprocesos de Posix (C en Unix) son un poco más complicados.

0

La concurrencia es básicamente poder realizar fork() procesos y calcular cosas en paralelo de la misma forma en que la administración de memoria básicamente puede llamar a malloc. Es parte de la historia, pero no toda. Ser capaz de simplificar los problemas relacionados con la concurrencia es la diferencia entre los idiomas que son buenos en concurrencia y los que solo pueden ser concurrentes.

+0

No. La simultaneidad no es paralela. –

2

En relación con su pregunta de por qué fork() en lugar de enhebrar: cuando utiliza procesos separados, obtiene la separación automática de espacios de direcciones.En programas multiproceso, es muy común que los hilos se comuniquen utilizando su memoria compartida (naturalmente). Esto es muy eficiente, pero también es difícil conseguir toda la sincronización entre hilos correcta, y es por eso que algunos lenguajes son mejores en multiprocesamiento que otros: proporcionan mejores abstracciones para manejar los casos comunes de comunicación entre hilos.

Con procesos separados, no tiene estos problemas en la misma medida. Normalmente, configura la comunicación entre los procesos para seguir algún tipo de patrón de paso de mensajes, que es más fácil de hacer bien. (Bueno, también puede usar memoria compartida entre procesos, pero eso no es tan común como el envío de mensajes.) En los sistemas Unix fork() ha sido típicamente muy barato, por lo que el diseño tradicional de programas concurrentes en Unix utiliza procesos y conductos para comunicarse entre ellos, pero en sistemas donde la creación de procesos es una operación costosa, a menudo se considera que los hilos son el mejor enfoque.

4

En los idiomas que no están diseñados para la concurrencia, debe confiar en las llamadas de bajo nivel del sistema y administrar muchas cosas usted mismo. Por el contrario, un lenguaje de programación diseñado para la concurrencia, como Erlang, proporcionará construcciones de alto nivel que ocultan los detalles de bajo nivel. Esto hace que sea más fácil razonar sobre la corrección de su código, y también da como resultado un código más portátil.

Además, en un lenguaje de programación diseñado para la concurrencia, normalmente hay solo un puñado de maneras de hacer cosas simultáneas, lo que conduce a la coherencia. Por el contrario, si el lenguaje de programación no se diseñó para la concurrencia, entonces las diferentes bibliotecas y los diferentes programadores harán las cosas de diferentes maneras, lo que dificulta tomar decisiones sobre cómo hacerlo.

Es un poco como la diferencia entre un lenguaje de programación con recolección de basura automatizada y uno sin. Sin la automatización, el programador tiene que pensar mucho sobre los detalles de implementación. La diferencia entre programación multiproceso y programación multiproceso (es decir, fork()) es que un programa multiproceso puede ser más eficiente porque los datos no tienen puede ser más robusto

2

Estoy estudiando el tema (ahora mismo: D) y una de las cosas que parece ser una diferencia muy importante en la concurrencia entre idiomas es el poder expresivo del lenguaje en la concurrencia.

Por ejemplo, C++ no tiene compatibilidad nativa con la concurrencia y depende de las funciones proporcionadas por el sistema operativo.

Java es un paso anterior porque tiene algunos métodos integrados, mientras que otros se dejan al sistema operativo (programación de hilos o prioridad, por ejemplo).

lugar uno de lo que parece ser uno de los mejores lenguajes de programación de apoyo concurrencia es Ada, que tiene en realidad un conjunto de concurrencia modelo construida en (programación y prioridad incluido).

¿Por qué es esto importante? ¡Debido a la portabilidad !

El uso de un lenguaje con buena potencia expresiva de concurrencia le permite llevar su programa simultáneo a Windows, Linux o Mac sin grandes temores sobre la forma en que funcionará. Por ejemplo: la prioridad de subproceso se aplicará en el de la misma manera en su programa Ada ejecutándose en Windows, Linux o Mac mientras que puede ser realmente diferente (ignorado en algunos SO y aplicado en otros) con Java o C++.

Esto es lo que me parece por el curso que estoy tomando en la universidad en este momento :)

+0

No estoy seguro de lo que quiere decir con soporte nativo. Parece que el estándar C++ tiene soporte para subprocesos http://stackoverflow.com/questions/218786/concurrent-programming-c – Parag

+0

El soporte para subprocesos se agregó a C++ en el estándar C++ 11, que se aceptó después de esta respuesta fue escrito. –

0

La elección de la lengua depende de la aplicación que desea hacer.

¿Desea crear un sistema altamente escalable, con muchas "solicitudes" entrantes? Entonces Erlang puede ser una buena opción. Se sabe que es una buena opción para escenarios de aplicaciones "altamente concurrentes".

Si desea escribir un juego típico y quiere que use las CPU de doble o cuádruple núcleo actualmente disponibles de su audiencia, entonces estará sujeto a diferentes decisiones (marcos, motores, bibliotecas, interfaces de hardware disponibles). En este caso, utilizará subprocesos y grupos de subprocesos para descargar el trabajo de procesamiento. Lo más probable es que use un tipo de cola de mensajes para comunicarse entre los hilos.

¡En el desarrollo web (del lado del servidor) es muy probable que ya hayas adquirido experiencia en programación simultánea! Tal vez no lo sabías, porque el lenguaje y el marco dado (tal vez Apache & PHP) te proporcionaron un entorno que te quitó la carga de tus hombros.

1

Para tenedor es humano para enhebrar es divina: D

bifurca implica el kernel y crea un espacio de direcciones independiente - lo que significa proc X e Y no pueden compartir y necesita usar primitivas IPC fácilmente, y la creación de un subproceso permite una sincronización en el proceso mucho más rápida que IPC, que implica interruptores de contexto de kernel por ambos procesos y rendimiento de subprocesos innecesarios (que involucran al kernel para activar dicho subproceso).

Sin embargo, hay una multitud de razones por las cuales los diferentes modelos de concurrencia son mejores que otros. Solo te estoy dando la regla general para la programación general. Por ejemplo, no bifurcar podría poner en peligro la lógica que podría separarse mediante bifurcación (me encanta esa palabra) - en peligro, porque si la otra lógica en el proceso falla, dicha lógica está disminuyendo con el proceso.