Langage de programmation où chaque appel / bloc de fonction se fait dans un thread séparé? [fermé]

26

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.)

Grimbox
la source
17
La création de threads est simple. L'astuce avec le multi-threading est quand ils ont besoin de se parler ou de travailler avec les mêmes ressources. En d'autres termes, ce n'est pas la fourche qui est difficile, ce sont les jointures. Le principal problème que vous devez résoudre est de savoir comment contrôler cela.
JimmyJames
20
OMI, vous ne pouvez pas faire cela sans étirer sérieusement la définition habituelle du mot "fonction" ou du mot "fil". Vous voudrez peut-être lire sur les acteurs si vous ne les connaissez pas déjà: en.wikipedia.org/wiki/Actor_model
Solomon Slow
9
Obtenez suffisamment de détails et vous constaterez que les processeurs parallélisent déjà automatiquement les instructions, sans imposer de charge supplémentaire au développeur de logiciels. Voir Exécution hors service et processeur superscalaire .
8bittree
8
Cela semble vraiment horrible. J'allais expliquer pourquoi, mais Karl Bielefeldt l'a déjà fait.
Mason Wheeler
1
Quel type de paradigme souhaitez-vous soutenir dans votre langue? Doit-elle être impérative ou fonctionnelle? Êtes-vous en train de dire que toutes les instructions seraient exécutées en même temps - les blocs then / else ainsi que ce qui les suit?
Bergi

Réponses:

39

chaque appel de fonction / nouveau bloc (clauses if, boucles, etc.) fonctionnera dans un thread séparé.

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.

Je me demande donc à quoi pourrait ressembler un tel langage sur le plan de la syntaxe

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.)

Basile Starynkevitch
la source
25
+1 pour la raison pour laquelle la syntaxe n'est pas pertinente. Un autre +1 si je pouvais pour expliquer pourquoi la syntaxe est très importante.
Jörg W Mittag
Bonne suggestion, mais pour discuter de choses sur LtU, vous voudriez un compte et ce n'est pas trivial d'en obtenir un de mon expérience.
Mael
1
Vous devez utiliser un pool de threads pour réduire les frais généraux. en.wikipedia.org/wiki/Thread_pool
shawnhcorey
37

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.

Karl Bielefeldt
la source
8
Je serais déjà heureux de travailler avec un PC démodé avec seulement des centaines de cœurs ...
Hagen von Eitzen
8
Je voudrais ajouter que pour les conceptions fortement parallèles aux données, nous avons déjà fait beaucoup de parallélisation très efficacement: les GPU sont essentiellement des machines de 200 à 1000 cœurs (ils ont même leur propre hiérarchie de mémoire).
Delioth
4
@HagenvonEitzen: L'Azul Vega JCA (Java Compute Appliance) avait 16 CPU avec 54 cœurs chacun pour un total de 864 cœurs, et ce n'était pas une machine de recherche ou un prototype, mais un vrai produit. Il ne remplissait pas non plus un bâtiment entier ou même une pièce entière, c'était un appareil de taille de bureau. Et il était disponible il y a 9 ans. Les GPU étaient déjà mentionnés, cependant, c'était une machine avec 864 cœurs de processeur à usage général .
Jörg W Mittag
3
Bien sûr, il y a une raison pour laquelle nous n'avons les massifs aujourd'hui GPU données parallèles, mais plus les CPU multi-core massif est pour les ordinateurs de bureau. Les premiers sont commercialement viables, les seconds ne le sont pas, et c'est parce que vous ne pouviez pas les programmer efficacement.
MSalters
@MSalters peut-être avons-nous juste besoin d'un nombre infini de singes? Ou, des programmes Quantum qui exécutent simplement toutes les opérations possibles à chaque étape?
15

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.

GenericJam
la source
4

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.

Artelius
la source
4

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?

Stig Hemmer
la source
Aucune infraction destinée à une langue ne figurant pas sur ma liste. C'est juste que mes connaissances sont limitées.
Stig Hemmer
3

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é.

Martin Maat
la source
5
C'est une excellente réponse à une question différente; OP ne demande pas la sagesse d'un tel schéma mais simplement s'il peut être fait et à quoi ressemblerait la "syntaxe".
DepressedDaniel
9
Ceux qui ne le demandent pas ont le plus besoin de ma sagesse. Si quelqu'un demande s'il est possible de descendre une colline dans un panier, la meilleure réponse ne serait pas "Vous pariez! Assurez-vous de bien graisser les roues!". Ce serait plutôt "Eh bien, oui, mais ...".
Martin Maat
Me rappelle l'ancienne instruction du langage d'assemblage EIAO - Exécuter dans n'importe quel ordre . (Et où est cette clé de toute façon?)
@MartinMaat personne ne va se tuer en écrivant un langage de programmation pour le plaisir
user253751
2

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.

foobar
la source
2

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.

Gustafc
la source
1
+1 pour avoir forgé une forteresse ... J'ai beaucoup aimé l'idée de la langue. J'étais vraiment triste quand ils ont annoncé l'arrêt du développement ...
Roland Tepp
2

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.

OnePie
la source
0

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?

MSalters
la source
Et, si vous tardez à répondre à une question assez longtemps, le besoin de réponse disparaît généralement. Je pense que cela s'appelle "Lazy Existing".