57 votes

Concurrence: comment la mémoire partagée par rapport au passage de messages gère-t-elle les structures de données volumineuses?

En regardant Aller et Erlang l'approche de la simultanéité, j'ai remarqué qu'ils reposent tous deux sur la transmission de messages.

Évidemment, cette approche réduit le complexe d'écluses, car il n'y a pas d'état partagé.

Cependant, prenons le cas de nombreux clients qui souhaitent un parallèle un accès en lecture seule à une seule grande structure de données en mémoire -- comme un suffixe tableau.

Mes questions:

  • Utilisation partagée de l'état d'être plus rapide et utilise moins de mémoire que la transmission de message, que les verrous sont pour la plupart inutiles, car les données sont en lecture seule, et n'a besoin d'exister dans un seul endroit?

  • Comment ce problème sera abordé dans un message en passant contexte? Y aurait-il un processus unique avec accès à la structure de données et les clients doivent simplement séquentiellement les données de la demande? Ou, si possible, les données seront découpées pour créer plusieurs processus qui détiennent des morceaux?

  • Compte tenu de l'architecture moderne de la CPU et de la mémoire, est-il beaucoup de différence entre les deux solutions, c'est à dire, de la mémoire partagée peut être lu en parallèle par plusieurs cœurs-à-dire il n'y a pas de matériel goulot d'étranglement qui serait autrement faire les deux implémentations environ effectuer la même?

28voto

rvirding Points 13019

Une chose à réaliser est que les Erlang simultanéité modèle n'est PAS vraiment préciser que les données dans les messages doivent être copiées entre les processus, il indique que l'envoi de messages est la seule façon de communiquer et qu'il n'existe pas à l'état partagé. Comme toutes les données sont immuables, ce qui est fondamental, puis une mise en œuvre peut très bien ne pas copier les données, mais il suffit d'envoyer une référence. Ou peut utiliser une combinaison de ces deux méthodes. Comme toujours, il n'y a pas de meilleure solution et il y a des arbitrages à faire en choisissant la façon de le faire.

Le FAISCEAU utilise la copie, sauf pour les gros fichiers binaires où il envoie une référence.

27voto

Javier Points 33134
  • Oui, l'état partagé pourrait être plus rapide dans ce cas. Mais seulement si vous pouvez renoncer à les serrures, et ce n'est faisable que si c'est absolument en lecture seule. si c'est "principalement en lecture seule", alors vous avez besoin d'un verrou (sauf si vous parvenez à écrire sans verrouillage des structures, être averti qu'ils sont même un peu plus subtil que les verrous), et puis vous auriez du mal à faire exécuter aussi vite qu'un bon passage de message d'architecture.

  • Oui, vous pourriez écrire un "processus de serveur" à la partager. Avec un très léger processus, il n'est pas plus lourd que l'écriture d'une petite API pour accéder aux données. Penser comme un objet (au sens de la programmation orientée objet) qui "possède" les données. Le fractionnement les données en blocs pour améliorer le parallélisme (appelé "sharding" en DB cercles) permet en gros de cas (ou si les données sont sur le stockage lent).

  • Même si NUMA est d'arriver à intégrer, vous avez encore plus et plus de cœurs par NUMA cellule. Et une grande différence, c'est qu'un message peut être transmis entre deux cœurs, tandis qu'un verrou doit être rincée à partir du cache sur TOUS les cœurs, en les limitant à l'inter-cellulaire de la latence du bus (même plus lent que l'accès à la RAM). Si quoi que ce soit, partagée-état/serrures devient de plus en plus irréalisable.

en bref.... obtenir utilisé pour la transmission de message et les processus du serveur, c'est à la mode.

Edit: un réexamen de cette réponse, je veux ajouter une phrase sur Aller de la documentation:

partager de la mémoire par la communication, ne pas communiquer par le partage de la mémoire.

l'idée est la suivante: lorsque vous avez un bloc de mémoire partagée entre les threads, la méthode classique pour éviter les accès concurrents est d'utiliser un verrou à l'arbitrage. Le Go style est de faire passer un message avec la référence, un seul thread accède à la mémoire lors de la réception du message. Il s'appuie sur un certain degré de programmeur de la discipline; mais très propre-à la recherche du code qui peut être facilement corrigé, il est donc relativement facile à déboguer.

l'avantage est que vous n'avez pas à copier de gros blocs de données sur chaque message, et ne pas avoir à efficacement évacuer vers les caches que sur certaines implémentations de verrouillage. C'est encore un peu tôt pour dire si le style conduit à des performances supérieures dessins ou pas. (surtout depuis cours d'exécution est un peu naïf sur la planification de thread)

12voto

Nick Johnson Points 79909

Dans Erlang, toutes les valeurs sont immuables. Il n'est donc pas nécessaire de copier un message lorsqu'il est envoyé entre des processus, car il ne peut de toute façon pas être modifié.

Dans Go, la transmission des messages se fait par convention: rien ne vous empêche d'envoyer un pointeur sur un canal, puis de modifier les données pointées, uniquement par convention; il n'est donc pas nécessaire de copier le message.

11voto

Greg Rogers Points 18119

La plupart des processeurs modernes utilisent des variantes du protocole MESI. En raison de l'état partagé, en Passant en lecture seule des données entre les différents threads est très bon marché. Modifié les données partagées sont très cher, cependant, parce que tous les autres caches stocker cette ligne de cache doit invalider.

Donc si vous avez des données en lecture seule, il est très bon marché pour le partager entre les threads au lieu de copier les messages. Si vous avez principalement en lecture de données, il peut être coûteux à partager entre les threads, en partie à cause de la nécessité de synchroniser l'accès, et en partie parce que les écritures de supprimer le cache comportement respectueux des données partagées.

Immuable structures de données peut être bénéfique ici. Au lieu de changer les données réelles de la structure, il vous suffit de faire un nouveau qui partage la plupart des anciennes données, mais les choses ont changé, que vous avez besoin de changé. Le partage d'une seule et unique version de c'est bon marché, puisque toutes les données sont immuables, mais vous pouvez toujours mettre à jour vers une nouvelle version de manière efficace.

3voto

Christian Points 7253

Une solution qui n'a pas été présenté ici est la réplication maître-esclave. Si vous avez une grande structure de données, vous pouvez répliquer les modifications à tous les esclaves qui effectuent la mise à jour sur leur copie.

Ceci est particulièrement intéressant si l'on veut à l'échelle de plusieurs machines qui n'ont même pas la possibilité de partager de la mémoire sans très artificielle configurations (mmap d'un bloc d'un dispositif de lecture/écriture à partir d'un ordinateur distant de mémoire?)

Une variante est d'avoir un gestionnaire de transactions que l'on demander gentiment de mettre à jour les données répliquées structure, et il fera en sorte que ça sert un seul et mise à jour-demande en même temps. C'est plus de l'amnésie & nbsp; modèle maître-maître de réplication de l'amnésie & nbsp; de la table de données, qui sont considérés comme des "grande structure de données".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X