Actualmente estoy creando un lenguaje de programación por diversión, donde la idea es que cada llamada de función / bloque nuevo (si las cláusulas, bucles, etc.) funcionarán en un hilo separado. En lugar de crear nuevos subprocesos, el estándar debería ser que lo haga automáticamente, y si desea que se ejecute en el subproceso principal, deberá especificarlo.
No estoy tan informado sobre la programación paralela de subprocesos múltiples, pero sí sé lo básico (Futuros, objetos seguros para subprocesos). Por lo tanto, me pregunto cómo podría ser un lenguaje semejante en cuanto a sintaxis y si es posible comenzar. El objetivo no es hacerlo "útil", es más por diversión y por una experiencia de aprendizaje.
(Lo siento si este es el lugar equivocado para publicar. De ser así, agradecería que me señalaras el lugar correcto donde se permite una pregunta como la mía).
Respuestas:
Lea mucho más sobre las continuaciones y el estilo de paso de continuación (y su relación con hilos o corutinas). Sugiero leer SICP y Lisp en piezas pequeñas . Además, Programming Language Pragmatics ofrece una visión general útil de varios lenguajes y le ayudará a diseñar el suyo propio.
La sintaxis no importa mucho para explorar ideas . La semántica importa mucho más. Sugiero adoptar una sintaxis similar a S-expr (para que pueda crear prototipos con Scheme y su llamada / cc ) al principio.
Una vez que sus ideas sean más claras (después de un poco de experimentación), podría discutirlas en lambda-the-ultimate , podría definir una sintaxis más sexy (que realmente importa si desea que las personas adopten su idioma, y lo que también importa es la calidad de implementación, una implementación de muestra de software libre, la documentación, la biblioteca estándar, la interfaz de funciones externas, etc.
fuente
Puede que le interese leer sobre la investigación en datos paralelos de Haskell . Si busca en YouTube, Simon Peyton Jones también ha dado algunas charlas interesantes relacionadas con el tema.
Si recuerdo correctamente de sus charlas, en programación puramente funcional, es casi trivial encontrar oportunidades para crear hilos. Su principal problema en su investigación es tener demasiados que son de corta duración, de modo que la sobrecarga de crear hilos y comunicar sus resultados esencialmente supera los beneficios del paralelismo. Por ejemplo, es fácil enseñarle a un compilador a girar 100 hilos para calcular
sum $ fmap (+1) <100 length vector>
, pero ¿valdrá la pena la sobrecarga?El truco consiste en consolidar los hilos en tamaños beneficiosos, sin imponer una carga en el programador para denotarlo manualmente. Es un problema difícil que debe resolverse para utilizar de manera efectiva futuras PC con miles de núcleos.
fuente
Esto es exactamente lo que hace Erlang. Se encarga de volver a unir los hilos principalmente mediante el uso de colas. Es un concepto brillante pero un poco difícil de entender inicialmente si su experiencia es más de lenguajes de tipo procesal. Recomiendo investigarlo.
fuente
En primer lugar, le recomendaría que consulte PROMELA , un lenguaje utilizado para describir un algoritmo concurrente, de modo que un verificador de modelos pueda aplicar la fuerza bruta a todas las ejecuciones posibles para verificar que sea incapaz de un comportamiento incorrecto. (La programación concurrente es notoriamente difícil de entender, por lo que tales técnicas de verificación son importantes). No ejecuta todas las construcciones en hilos separados, pero tiene una sintaxis y semántica bastante extraña porque su enfoque es el no determinismo de los programas concurrentes.
Yendo más abstracto, el cálculo π es un enfoque hermoso para modelar computación paralela. Es difícil entenderlo a menos que obtenga el libro Communicating and Mobile Systems: The Pi Calculus , de Robin Milner. Me ayudó a pensar en la computación paralela en un sentido más amplio que "múltiples hilos que acceden a una memoria compartida". Es bastante interesante cómo se pueden construir enunciados condicionales, "gotos", etc., a partir de primitivas más simples, naturalmente paralelas.
Con respecto a la sintaxis ... la mejor manera de resolver esto es escribir algunos programas de muestra. Escriba un programa para ordenar una matriz, o haga ping simultáneamente a varios servidores e informe cuál responde más rápido, o intente resolver un laberinto en paralelo, o lo que sea. Mientras hace esto, las cosas que faltan en su sintaxis se harán evidentes y puede agregarlas. Después de haber agregado varias cosas, pregúntese si tienen algo en común y, de ser así, tal vez pueda encontrar un enfoque más simple que pueda tener múltiples propósitos.
fuente
Proyectos similares se han intentado en el pasado. Sugiero leer sobre los clásicos para saquear ideas. (Todos los enlaces van a Wikipedia)
Unidad Este lenguaje fue / es usado para enseñar programación paralela. No creo que se haya implementado realmente. La sintaxis es algo críptica, pero básicamente tiene una colección de declaraciones que se ejecutan en un orden desconocido y repetidamente hasta que no hay nada más que hacer. Esto es lo más cercano a lo que pides.
Occam Este lenguaje fue diseñado para usarlo realmente, pero nunca lo entendió. Aquí hay una palabra clave PAR que significa que una lista de declaraciones debe ejecutarse en paralelo.
Erlang Otro idioma del mundo real. Este es utilizado por la compañía de telecomunicaciones Ericsson y tiene muchos seguidores. Han trabajado mucho para hacer que el paralelismo sea práctico y utilizable.
Google GO Este es mi favorito del grupo. Conceptualmente es lo mismo que Erlang, pero con una mejor sintaxis y el peso de Google detrás. ¿Qué podría salir mal?
Me gustaría cerrar con una advertencia: el paralelismo es muy difícil de acertar. La mayoría de los errores en los programas modernos son el resultado de equivocarse . ¿Estás seguro de que quieres ir allí?
fuente
Es posible, pero no sería útil para más del 99% de todas las aplicaciones pensables. La lógica está típicamente unida a la secuencia, es un flujo. Paso a paso, llega a una solución a un problema y el orden de los pasos es importante, principalmente porque la salida de un paso se ingresará para el siguiente.
En los pocos casos que tiene muchas tareas que se pueden realizar independientemente una de la otra, generalmente es barato configurarlas secuencialmente antes de permitir que se ejecuten en paralelo.
Por lo tanto, creo que sería mejor dedicar su tiempo a aprender cómo usar las funciones de subprocesos múltiples en su lenguaje de programación favorito.
fuente
Clojure puede valer la pena ver algunas ideas.
http://clojure-doc.org/articles/language/concurrency_and_parallelism.html
Aquí hay algunos pensamientos: si llamamos a una unidad de cómputo que se puede realizar de forma independiente una tarea: 1. Las tareas son independientes, por lo que se pueden ejecutar de forma simultánea 2. Las diferentes tareas requieren diferentes recursos y requieren diferentes tiempos para ejecutarse 3. Por lo tanto, las tareas deben programarse para un rendimiento máximo 4. El único programa en condiciones de actuar como planificador es el sistema operativo
Cosas como el despacho central de las manzanas son un intento de proporcionar un planificador de este tipo.
Lo anterior significa que la responsabilidad de ejecutar tareas no es necesariamente la del lenguaje de programación.
Una segunda idea es reducir la carga de programar sistemas paralelos tanto como sea posible. La única forma de hacerlo es eliminar cualquier especificación de cómo se debe hacer algo desde el programa. Un programa solo debe especificar lo que se debe hacer y el resto debe suceder automáticamente.
Lo anterior probablemente significa que los lenguajes dinámicos y la compilación justo a tiempo son el camino a seguir.
fuente
Lo que estás buscando se llama paralelismo implícito, y hay lenguajes que han explorado este concepto, como Sun / Oracle's Fortress . Entre otras cosas, (potencialmente) ejecuta bucles en paralelo.
Desafortunadamente, se ha descontinuado y hay muchos enlaces muertos por ahí, pero aún puede encontrar algunos archivos PDF flotando por ahí, si googlea lo suficiente:
https://www.eecis.udel.edu/~cavazos/cisc879-spring2008/papers/fortress.pdf (la especificación del idioma)
http://stephane.ducasse.free.fr/Teaching/CoursAnnecy/0506-Master/ForPresentations/Fortress-PLDITutorialSlides9Jun2006.pdf
http://www.oracle.com/technetwork/systems/ts-5206-159453.pdf
http://dl.acm.org/citation.cfm?id=1122972 (pagado)
Vale la pena señalar que, por lo general, no querría comenzar un hilo real para cada declaración / expresión, ya que crear e iniciar hilos tiende a ser costoso; en cambio, tendría un grupo de hilos en los que publicará fragmentos de trabajo que deben realizarse . Pero ese es un detalle de implementación.
fuente
Si bien no es un lenguaje de programación como tal, debería echar un vistazo a VHDL . Se utiliza para describir los circuitos digitales, que naturalmente hacen todo en paralelo a menos que usted le indique específicamente que lo haga en serie. Podría darle algunas ideas sobre cómo diseñar su lenguaje y para qué tipo de lógica podría ser adecuada.
fuente
Esto se puede simular con bastante facilidad en C ++. Solo asegúrese de que "cada" función de llamada sea implementada por a
std::future
. El manejo del valor de retorno se realiza simplemente llamando.get()
al futuro.Por lo tanto, puede crear prototipos de su lenguaje compilando en C ++. Esto también nos dice cómo se vería la sintaxis: la principal diferencia es que separa el punto de llamada (donde se proporcionan los argumentos de entrada) del punto de retorno (donde se usa la salida de la función).
(*) Digo "cada función", pero depende de usted lo que cuenta como una función. ¿Es
memset
un intrínseco o una función? ¿La asignación de enteros o la asignación de tipos definidos por el usuario es una llamada de función?fuente