2008-10-28 5 views
61

Quelqu'un peut-il expliquer la structure d'un Pid à Erlang?Quelqu'un peut-il expliquer la structure d'un Pid à Erlang?

Pids ressemble à ceci: <A.B.C>, par exemple < 0.30.0>, mais je voudrais savoir quelle est la signification de ces trois "bits": A, B et C.

'A' semble toujours être 0 sur un noeud local, mais cette valeur change lorsque le propriétaire du Pid est situé sur un autre noeud.

Est-il possible d'envoyer directement un message sur un nœud distant en utilisant uniquement le Pid? Quelque chose comme ça: < 4568.30.0>! Message, sans avoir à spécifier explicitement le nom du processus enregistré et le nom du nœud ({proc_name, Node}! Message)?

+0

Ok, mon problème principal est corrigé. Je n'ai simplement pas envoyé le bon pid au côté distant ... – jideel

Répondre

64

processus imprimés ids < ABC> sont composés de 6:

  • A, le numéro de noeud (0 est la locale noeud, un nombre arbitraire d'un noeud distant)
  • B, les 15 premiers bits du numéro de processus (un indice dans la table des processus) 7
  • C, les bits 16-18 du processus numéro (même numéro de processus que B) 7

En interne, le numéro de processus est de 28 bits de large sur l'émulateur 32 bits. La définition étrange de B et C provient de R9B et des versions antérieures d'Erlang dans lesquelles B était un ID de processus 15bit et C était un compteur de retour incrémenté lorsque l'ID de processus max était atteint et que les ID inférieurs étaient réutilisés.

Dans la distribution erlang, les PID sont un peu plus gros car ils incluent l'atome du noeud ainsi que les autres informations. (Distributed PID format)

Lorsqu'un PID interne est envoyé d'un noeud à l'autre, il est automatiquement converti en la forme PID externe/distribuée, de sorte que ce qui pourrait être <0.10.0> (inet_db) sur un noeud pourrait finir comme <2265.10.0> lorsqu'il est envoyé à un autre noeud. Vous pouvez simplement envoyer à ces PID comme d'habitude.

% get the PID of the user server on OtherNode 
RemoteUser = rpc:call(OtherNode, erlang,whereis,[user]), 

true = is_pid(RemoteUser), 

% send message to remote PID 
RemoteUser ! ignore_this, 

% print "Hello from <nodename>\n" on the remote node's console. 
io:format(RemoteUser, "Hello from ~p~n", [node()]). 

Pour plus d'informations, voir: Internal PID structure, Node creation information, Node creation counter interaction with EPMD

+1

Il s'avère que j'avais tort sur le compteur de création après avoir regardé la source de près. Merci à Wallentin de m'avoir invité à le faire. Je suis maintenant sûr de la taille des bits de B et C, mais je n'ai pas suivi complètement la macro _GET_BITS dans la source erts, donc je ne sais pas si j'ai raison sur les bits de haut en bas. – archaelus

2

Le PID fait référence à un processus et à une table de nœuds. Vous ne pouvez donc envoyer un message directement à un PID que s'il est connu dans le nœud à partir duquel vous effectuez l'appel.

Il est possible que cela fonctionne si le noeud sur lequel vous appelez déjà knows about est le noeud sur lequel le processus s'exécute.

+1

si je lance "nodes()" sur le noeud distant, mon noeud local apparaît, mais je ne peux pas enregistrer le "remote pid", car list_to_pid échoue: "register (client, list_to_pid (" <5058.95.0> "))." renvoie "mauvais argument". Ai-je raté quelque chose? – jideel

+0

Vous ne pouvez enregistrer que des pids locaux - pour enregistrer des pids distants, vous devez utiliser le module d'enregistrement global (ou lancer votre propre système d'enregistrement). – archaelus

13

Si je me souviens bien, le format est <nodeid,serial,creation>. 0 est le noeud courant tout comme un ordinateur a toujours le nom d'hôte "localhost" pour se référer à lui-même. C'est par ancien souvenir, donc il pourrait ne pas être 100% correct dur.

Mais oui. Vous pourriez construire le pid avec list_to_pid/1 par exemple.

PidString = "<0.39.0>", 
list_to_pid(PidString) ! message. 

Bien sûr. Vous utilisez simplement la méthode que vous devez utiliser pour construire votre PidString. Probablement écrire une fonction qui génère et utiliser à la place de PidString comme tel:

list_to_pid(make_pid_from_term({proc_name, Node})) ! message 
+0

Avez-vous vu ce gros avertissement rouge? [list_to_pid/1] (http://www.erlang.org/doc/man/erlang.html#list_to_pid-1) Et aussi vous pouvez simplement envoyer {proc_name, Node}! message ou utilisez le module global si vous souhaitez utiliser des noms globaux. –

+0

Ouais .. Connaissez ces autres méthodes. Et c'est ce que j'utilise. Ce n'était tout simplement pas la question. :) –

+0

pid_to_list/1 prend un pid et retourne sa représentation sous forme de chaîne. – mcandre

7

ID de processus < ABC> est composé de:

  • A, identifiant de noeud qui ne sont pas arbitraires, mais l'indice interne pour ce noeud dans dist_entry. (Il s'agit en fait de l'entier de l'atome pour le nom du nœud.)
  • B, indice de processus qui fait référence à l'index interne dans le proctab, (0 -> MAXPROCS).
  • C, série qui augmente chaque fois que MAXPROCS a été atteint.

La balise de création de 2 bits n'est pas affichée dans le pid mais est utilisée en interne et augmente chaque fois que le nœud redémarre.

+0

+1 pour les bits de création – ron

0

En dehors de ce que les autres ont dit, vous pouvez trouver cette simple expérience utile pour comprendre ce qui se passe en interne:

1> node(). 
[email protected] 
2> term_to_binary(node()). 
<<131,100,0,13,110,111,110,111,100,101,64,110,111,104,111, 
    115,116>> 
3> self().     
<0.32.0> 
4> term_to_binary(self()). 
<<131,103,100,0,13,110,111,110,111,100,101,64,110,111,104, 
    111,115,116,0,0,0,32,0,0,0,0,0>> 

Ainsi, vous pouvez se que le nom de noeud est stocké en interne dans le pid. Plus d'info dans this section de Learn You Some Erlang.