Multi-core et simultanéité - Langages, bibliothèques et techniques de développement [fermé]
-
02-07-2019 - |
Question
Le paysage de l’architecture de la CPU a changé. La création de logiciels repose sur plusieurs cœurs. J'ai réalisé un développement multithread en C, C ++ et Java, ainsi que plusieurs processus IPC utilisant divers mécanismes IPC. Les approches traditionnelles consistant à utiliser des threads ne semblent pas permettre, pour le développeur, d’utiliser un matériel prenant en charge un degré élevé de simultanéité.
Quelles langues, bibliothèques et techniques de développement connaissez-vous qui permettent d’atténuer les problèmes traditionnels liés à la création d’applications simultanées? Je pense évidemment à des problèmes tels que les blocages et les conditions de course. Les techniques de conception, les bibliothèques, les outils, etc. sont également intéressants, car ils permettent de tirer pleinement parti des ressources disponibles et de s’assurer que celles-ci sont utilisées. Le simple fait d’écrire une application thread sécurisée et robuste ne garantit pas qu’elle utilise tous les cœurs disponibles.
Ce que j'ai vu jusqu'à présent est:
- Erlang : processus basé sur la transmission de messages, IPC, le modèle de concurrence de l'acteur
- Dramatis : bibliothèque de modèles d'acteurs pour Ruby et Python
- Scala : langage de programmation fonctionnel de la machine virtuelle Java avec prise en charge ajoutée de la simultanéité
- Clojure : langage de programmation fonctionnel de la machine virtuelle Java avec une bibliothèque d'acteurs
- Termite : un portage de l'approche processus d'Erlang et du message transmis à Scheme
Que savez-vous d'autre, qu'est-ce qui a fonctionné pour vous et qu'est-ce qui vous semble intéressant à regarder?
La solution
Je suggérerais deux changements de paradigme:
Mémoire transactionnelle logicielle
Vous voudrez peut-être examiner le concept de mémoire transactionnelle logicielle (STM). L’idée est d’utiliser la concurrence concurrente optimiste : toute opération exécutée en parallèle par d’autres tente de terminer son travail dans une transaction isolée; si, à un moment donné, une autre transaction validant les données sur lesquelles cette transaction fonctionne a été invalidée, le travail de la transaction est abandonné et la transaction est réexécutée.
Je pense que la première implémentation largement connue de l'idée (sinon la preuve de concept et la première) est celle de Haskell: Articles et présentations sur la mémoire transactionnelle en Haskell . De nombreuses autres implémentations sont répertoriées dans l’article sur STM de Wikipedia .
Événement en boucle et promesses
Une autre façon très différente de gérer la concurrence est mise en œuvre dans le [langage de programmation E] ( http://en.wikipedia.org/wiki/E_ (langage de programmation% 29) .
Notez que sa façon de traiter la concurrence, ainsi que d'autres parties de la conception du langage, est fortement basée sur le modèle Actor.
Autres conseils
Vous avez mentionné Java, mais vous ne mentionnez que les threads. Avez-vous examiné la bibliothèque simultanée de Java? Il est livré avec Java 5 et supérieur.
C'est une très belle bibliothèque contenant des ThreadPools, CopyOnWriteCollections, pour n'en nommer que quelques-uns. Consultez la documentation dans le didacticiel Java . Ou si vous préférez, Java docs .
Quelques éléments basés sur Scala:
- PiLib: un langage hébergé pour Pi Concurrence simultanée de style de calcul
- Programmation événementielle sans inversion de contrôle
- Acteurs qui unifient les threads et les événements
- Acteurs de multidiffusion Scala: architecture et mise en oeuvre
- Implémentation de jointures à l'aide de la correspondance de modèle étendue
- Objets Scala communicants (Révisé )
J'ai utilisé le traitement pour Python. Il imite l'API du module threading et est donc très facile à utiliser.
Si vous utilisez map / imap
ou une compréhension de générateur / liste, la conversion de votre code pour utiliser le traitement
est simple:
def do_something(x):
return x**(x*x)
results = [do_something(n) for n in range(10000)]
peut être mis en parallèle avec
import processing
pool = processing.Pool(processing.cpuCount())
results = pool.map(do_something, range(10000))
qui utilisera le nombre de processeurs nécessaires pour calculer les résultats. Il existe également des variantes paresseuses ( Pool.imap
) et asynchrones ( Pool.map_async
).
Il existe une classe de file d'attente qui implémente Queue.Queue
et des travailleurs similaires aux threads.
Les pièges
Le traitement
est basé sur fork ()
, qui doit être émulé sous Windows. Les objets sont transférés via pickle
/ unpickle
, vous devez donc vous assurer que cela fonctionne. Créer un processus qui a déjà acquis des ressources n'est peut-être pas ce que vous voulez (pensez aux connexions de base de données), mais en général cela fonctionne. Cela fonctionne tellement bien qu’il a été ajouté à Python 2.6 en accéléré (cf. PEP -317 ).
Je dirais:
Modèles: threads + état partagé, acteurs + transmission de messages, mémoire transactionnelle, mappage / réduction? Langues: Erlang, Io, Scala, Clojure, Reia Bibliothèques: Retlang, Jetlang, Kilim, Cilk ++, fork / rejoindre, MPI, Kamaelia, Terracotta ??p>
Je tiens un blog sur les liens d'accès simultané sur des sujets comme celui-ci (Erlang, Scala, threading Java, modèle d'acteur, etc.) et j'affiche quelques liens par jour:
Je fais de la programmation simultanée à Ada depuis près de 20 ans maintenant.
Le langage lui-même (pas une bibliothèque intégrée) prend en charge les threads ("tâches"), plusieurs modèles de planification et plusieurs paradigmes de synchronisation. Vous pouvez même créer vos propres schémas de synchronisation en utilisant les primitives intégrées.
Vous pouvez penser au rendezvous d'Ada comme une sorte de Fonction de synchronisation orientée vers les procédures, tout en protected les objets sont plus orientés objet. Les rendez-vous ressemblent à l'ancien concept CS de moniteurs , mais beaucoup plus puissants. Les objets protégés sont des types spéciaux avec des primitives de synchronisation qui vous permettent de construire des objets exactement comme des verrous de système d'exploitation, des sémaphores, des événements, etc. Cependant, il est suffisamment puissant pour que vous puissiez également inventer et créer vos propres types d'objets de synchronisation, en fonction de vos besoins. .
La question Quoi modèle de programmation parallèle recommandez-vous aujourd’hui de tirer parti des multiples processeurs de demain? a déjà été demandé. J'ai également donné la réponse suivante.
Kamaelia est un cadre python permettant de créer des applications avec beaucoup de communication. processus.
Voici une vidéo de Pycon 2009. Elle commence par comparer Kamaelia à Twisted et Parallel Python, puis donne une démonstration pratique de Kamaelia.Kamaelia - La concurrence est utile, amusant
En Kamaelia, vous construisez des systèmes à partir de composants simples qui se parlent . Cela accélère le développement, facilite considérablement la maintenance et vous permet également de créer un logiciel naturellement concurrent . Il est destiné à être accessible par tous les développeurs, y compris les novices. C'est aussi amusant :)
Quel type de systèmes? Serveurs de réseau, clients, applications de bureau, jeux basés sur Pygame, systèmes de transcodage et pipelines, systèmes de télévision numérique, suppresseurs de spam, outils pédagogiques et bien plus encore :)
Accès concurrentiel facile avec Kamaelia - Partie 1 (59:08)
Accès concurrentiel facile avec Kamaelia - Partie 2 (18h15)
Je surveille de près les extensions parallèles pour .NET <. / a> et LINQ parallèle .
Je connais Reia , un langage basé sur Erlang mais qui a l'air plus comme Python / Ruby.
Cette question est étroitement liée à, sinon une copie de, Quel modèle de programmation parallèle recommandez-vous aujourd'hui pour tirer parti des multiples processeurs de demain?
Java possède également une bibliothèque d'acteurs . Et saviez-vous que J ava est un langage fonctionnel? ;)
OpenMP .
Il gère les threads pour vous, de sorte que vous ne vous souciez que des parties de votre application C ++ que vous souhaitez exécuter en parallèle.
par exemple.
#pragma omp parallel for
for (int i=0; i < SIZE; i++)
{
// do something with an element
}
le code ci-dessus exécutera la boucle for sur autant de threads que vous avez demandé à l'open runtime d'utiliser. Par conséquent, si SIZE est égal à 100 et que vous avez une boîte quad-core, cette boucle for exécutera 25 éléments sur chaque noyau.
Il existe quelques autres extensions parallèles pour différentes langues, mais celles qui m'intéressent le plus sont celles qui fonctionnent sur votre carte graphique. C'est un vrai traitement parallèle :) (exemples: GPU ++ et libSh )
C ++ 0x fournira des fonctions std :: lock
pour verrouiller plusieurs mutex ensemble. Cela contribuera à réduire le blocage en raison d'un verrouillage en panne. De plus, la bibliothèque de threads C ++ 0x comportera des promesses, des futures et des tâches empaquetées, permettant à un thread d'attendre le résultat d'une opération effectuée sur un autre thread sans aucun verrou de niveau utilisateur.
multitraitement
est une bibliothèque python qui simplifie la programmation multicœur, comme indiqué dans une autre réponse.
Le programme écrit avec le multitraitement
de python peut facilement être modifié pour être envoyé sur le cloud plutôt que sur des cœurs locaux. piCloud en tire parti pour fournir une puissance de traitement importante et à la demande sur le cloud: il vous suffit de modifier 2 lignes de votre code.
Alors, voici ce qu’il faut retenir: lorsqu’on choisit une bibliothèque multi-cœur, on peut s’interroger sur l’utilité d’une approche basée sur le cloud.