Je suis en train de créer un langage de programmation pour le plaisir où l'idée est que chaque appel de fonction / nouveau bloc (clauses if, boucles, etc.) fonctionnera dans un thread séparé. Au lieu de créer de nouveaux threads, la norme devrait être qu'il le fasse automatiquement, et si vous voulez qu'il s'exécute dans le thread principal, vous devrez le spécifier.
Je ne suis pas très informé sur la programmation parallèle multi-thread mais je connais les bases (Futures, objets thread-safe). Par conséquent, je me demande à quoi pourrait ressembler un tel langage sur le plan de la syntaxe et s'il est même possible de commencer par? Le but n'est pas de le rendre "utile", c'est plus pour le plaisir et une expérience d'apprentissage.
(Je suis désolé si ce n'est pas le bon endroit pour poster. Si c'est le cas, j'apprécierais volontiers si vous me dirigez vers le bon endroit où une question comme la mienne est autorisée.)
la source
Réponses:
En savoir plus sur les continuations et le style de passage de continuation (et leur relation avec les threads ou les coroutines) Je suggère de lire SICP & Lisp In Small Pieces . De plus, la programmation du langage pragmatique donne un aperçu utile de plusieurs langages et vous aiderait à concevoir le vôtre.
La syntaxe n'a pas beaucoup d'importance pour explorer des idées . La sémantique importe beaucoup plus. Je suggère d'adopter une syntaxe similaire à S-expr (afin que vous puissiez prototyper en utilisant Scheme et son appel / cc ) dans un premier temps.
Une fois que vos idées sont plus claires (après quelques expérimentations), vous pouvez en discuter sur lambda-the-ultimate , vous pouvez définir une syntaxe plus sexy (ce qui compte vraiment si vous voulez que les gens adoptent votre langue, et ce qui compte aussi, c'est la qualité d'implémentation, un exemple d'implémentation de logiciel gratuit, la documentation, la bibliothèque standard, l'interface de fonction étrangère, etc.)
la source
Vous pourriez être intéressé par la lecture de la recherche sur les données parallèles Haskell . Si vous effectuez une recherche sur youtube, Simon Peyton Jones a également donné des conférences intéressantes sur le sujet.
Si je me souviens bien de ses exposés, en programmation fonctionnelle pure, il est presque trivial de trouver des opportunités de créer des threads. Son principal problème dans ses recherches est d'en avoir trop qui sont de courte durée, de sorte que la surcharge de création de threads et de communication de leurs résultats l'emporte essentiellement sur les avantages du parallélisme. Par exemple, il est facile d'apprendre à un compilateur à faire tourner 100 threads pour calculer
sum $ fmap (+1) <100 length vector>
, mais le surcoût en va-t-il la peine?L'astuce consiste alors à consolider les threads dans des tailles avantageuses, sans imposer au programmeur le fardeau de l'indiquer manuellement. C'est un problème difficile qui doit être résolu afin d'utiliser efficacement les futurs PC avec des milliers de cœurs.
la source
C'est exactement ce que fait Erlang. Il gère la jonction des threads principalement à l'aide de files d'attente. C'est un concept génial mais un peu difficile à comprendre au départ si votre arrière-plan est plus des langages de type procédural. Je recommande fortement de l'examiner.
la source
Tout d'abord, je vous recommande de regarder PROMELA , un langage utilisé pour décrire un algorithme simultané afin qu'un vérificateur de modèle puisse forcer toutes les exécutions possibles pour vérifier qu'il est incapable d'un comportement incorrect. (La programmation simultanée est notoirement difficile à obtenir correctement, c'est pourquoi de telles techniques de vérification sont importantes.) Il n'exécute pas toutes les constructions dans des threads séparés, mais il a une syntaxe et une sémantique plutôt étranges car son objectif est le non - déterminisme des programmes simultanés.
Plus abstrait, le π-calcul est une belle approche pour modéliser le calcul parallèle. Il est difficile de se mettre en tête à moins d'obtenir le livre Communicating and Mobile Systems: The Pi Calculus , de Robin Milner. Cela m'a aidé à penser au calcul parallèle dans un sens plus large que "plusieurs threads accédant à une mémoire partagée". Il est assez intéressant de voir comment les instructions conditionnelles, les "gotos" et ainsi de suite peuvent être construits à partir de primitives naturellement plus simples et parallèles.
En ce qui concerne la syntaxe ... la meilleure façon de résoudre ce problème est d'écrire quelques exemples de programmes. Écrivez un programme pour trier un tableau, ou envoyez simultanément une requête ping à plusieurs serveurs et signalez lequel répond le plus rapidement, ou essayez de résoudre un labyrinthe en parallèle, ou autre chose. Pendant que vous effectuez cette opération, les éléments manquants dans votre syntaxe deviendront apparents et vous pourrez les ajouter. Après avoir ajouté plusieurs éléments, demandez-vous s'ils ont quelque chose en commun et, dans l'affirmative, vous pourrez peut-être trouver une approche plus simple pouvant servir à plusieurs fins.
la source
Des projets similaires ont été tentés par le passé. Je suggère de lire sur les classiques pour piller des idées. (Tous les liens vont à Wikipedia)
Unity Ce langage a été / est utilisé pour enseigner la programmation parallèle. Je ne pense pas qu'il ait été effectivement mis en œuvre. La syntaxe est quelque peu cryptique, mais fondamentalement, vous avez une collection d'instructions qui s'exécutent dans un ordre inconnu et à plusieurs reprises jusqu'à ce qu'il n'y ait plus rien à faire. C'est le plus proche de ce que vous demandez.
Occam Ce langage a été conçu pour être réellement utilisé mais il n'a jamais vraiment fait son chemin. Ici, il y a un mot-clé PAR qui signifie qu'une liste d'instructions doit être exécutée en parallèle.
Erlang Une autre langue du monde réel. Celui-ci est utilisé par la société de télécommunications Ericsson et a tout un suite. Ils ont beaucoup travaillé pour rendre le parallélisme pratique et utilisable.
Google GO C'est mon préféré du groupe. Conceptuellement la même chose qu'Erlang, mais avec une meilleure syntaxe et le poids de Google derrière. Qu'est-ce qui pourrait mal tourner?
Je voudrais terminer par un avertissement: le parallélisme est très difficile à obtenir correctement. La plupart des bogues dans les programmes modernes sont le résultat d'une erreur . Êtes-vous sûr de vouloir y aller?
la source
C'est possible mais cela ne serait pas utile pour 99 +% de toutes les applications imaginables. La logique est typiquement liée à une séquence, c'est un flux. Étape par étape, vous arrivez à une solution à un problème et l'ordre des étapes est important, principalement parce que la sortie d'une étape sera entrée pour la suivante.
Dans les rares cas où vous avez beaucoup de tâches qui peuvent être effectuées indépendamment les unes des autres, il est généralement bon marché de les configurer séquentiellement avant de les laisser s'exécuter en parallèle.
Donc, je pense que votre temps serait mieux consacré à apprendre à utiliser les fonctionnalités multi-threading dans votre langage de programmation préféré.
la source
Clojure peut valoir le coup d'œil pour quelques idées.
http://clojure-doc.org/articles/language/concurrency_and_parallelism.html
Voici quelques réflexions: Si nous appelons une unité de calcul qui peut être effectuée indépendamment une tâche: 1. Les tâches sont indépendantes et peuvent donc être exécutées simultanément 2. Différentes tâches nécessitent des ressources différentes et prennent des temps différents pour s'exécuter 3. Par conséquent, les tâches doivent être planifiées pour un débit maximal 4. Le seul programme en mesure d'agir en tant que planificateur est le système d'exploitation
Des choses comme la répartition centrale des pommes sont une tentative de fournir un tel programmateur.
Ce qui précède signifie que la responsabilité de l'exécution des tâches n'est pas nécessairement celle du langage de programmation.
Une seconde réflexion est de réduire au maximum la charge de programmation des systèmes parallèles. La seule façon de le faire est de supprimer toute spécification de la façon dont quelque chose doit être fait du programme. Un programme ne doit spécifier que ce qui doit être fait et le reste doit se produire automatiquement.
Ce qui précède signifie probablement que les langages dynamiques et la compilation juste à temps sont la voie à suivre.
la source
Ce que vous recherchez s'appelle le parallélisme implicite, et il existe des langages qui ont exploré ce concept, comme la forteresse de Sun / Oracle . Entre autres choses, il exécute (potentiellement) des boucles en parallèle.
Malheureusement, il a été interrompu et il y a beaucoup de liens morts, mais vous pouvez toujours trouver quelques PDF flottant là-bas, si vous cherchez assez sur Google:
https://www.eecis.udel.edu/~cavazos/cisc879-spring2008/papers/fortress.pdf (la spécification de langue)
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 (paywalled)
Il convient de noter que vous ne voudriez généralement pas démarrer un thread réel pour chaque instruction / expression, car la création et le démarrage de threads ont tendance à être coûteux - à la place, vous auriez un pool de threads sur lesquels vous publiez des morceaux de travail à faire . Mais c'est un détail d'implémentation.
la source
Bien qu'il ne s'agisse pas d'un langage de programmation en tant que tel, vous devriez jeter un œil à VHDL . Il est utilisé pour décrire les circuits numériques, qui font naturellement tout en parallèle, sauf si vous lui demandez spécifiquement de le faire en série. Cela pourrait vous donner des idées à la fois sur la conception de votre langage et sur le type de logique auquel il pourrait convenir.
la source
Cela peut être simulé assez facilement en C ++. Assurez-vous simplement que "chaque" * appel de fonction est implémenté par a
std::future
. La gestion de la valeur de retour se fait simplement en faisant appel.get()
à l'avenir.Par conséquent, vous pouvez prototyper votre langage en le compilant en C ++. Cela nous indique également à quoi ressemblerait la syntaxe: la principale différence est que vous séparez le point d'appel (où les arguments d'entrée sont fournis) du point de retour (où la sortie de la fonction est utilisée).
(*) Je dis "toutes les fonctions" mais c'est à vous de décider ce qui compte comme fonction. Est
memset
-ce intrinsèque ou une fonction? L'affectation d'entiers ou l'affectation de types définis par l'utilisateur est-elle un appel de fonction?la source