7
votes

Comment faites-vous des reçus sélectifs dans Gen_Servers?

J'ai porté la plupart de mes applications aux comportements OTP, mais je suis coincé. Je ne peux pas comprendre comment faire des reçus sélectifs à l'aide d'un Gen_Server. Si aucune des clauses de fonctions de rappel ne correspondent à un message, plutôt que de remettre le message dans la boîte aux lettres, elle est erronée!

Maintenant, partout où je vais, les gens Laud sélectifs reçoivent. Partout où je vais, les gens louches OTP. Peut-il vraiment être vrai que vous ne pouvez pas avoir à la fois à la fois? Ce n'est-ce pas comme une lacune majeure et corrigeable?

Comment les programmeurs Erlang gèrent-ils cela?

Edit (répondant au commentaire de Zed):

Voici un Exemple où j'aimerais voir une liste d'entiers imprimés dans la commande triée: xxx

bien sûr, dans ma vraie application, il y a des retards de minuterie et les messages qui doivent être traitée dans l'ordre sont entrelacés avec d'autres messages. En particulier, j'envoie des demandes HTTP, parfois nombreuses à la fois, parfois une à la fois avec un intervalle entre eux. En tout cas, je dois les recueillir dans l'ordre.


1 commentaires

Que voudriez-vous réaliser?


5 Réponses :


4
votes

Gen_Server n'est probablement pas le meilleur choix pour cela. Une chose que vous pouvez faire est de recevoir tous les messages dans une liste de mémoire tampon et d'implémenter le sélectif Recevez-vous vous-même:

handle_cast(test, _State) ->
    ...
    {noreply, {[1,2,4,5,6,7,8,9], []}};

handle_cast({result, N}, {Wait, Buff}) ->
    {noreply, handle_results(Wait, [N|Buff])}.

handle_results([], Buff) ->
    {[], Buff};

handle_results([W|WTail] = Wait, Buff) ->
    case lists:member(W, Buff) of
        true ->
            io:format("result: " ++ integer_to_list(W) ++ "~n"),
            handle_results(WTail, Buff -- [W]);
        false ->
            {Wait, Buff}
    end.


2 commentaires

Juste pour des raisons de complétude, vous pouvez renvoyer tous les messages indésirables à vous-même (le déplaçant ainsi à la fin de votre boîte aux lettres). Cela a de nombreux problèmes (votre Gen_Server fonctionnera sur l'accélération complète des messages d'aller d'avant en arrière; il utilise des spécificités de la mise en œuvre), de sorte que vous ne devriez donc pas l'utiliser jamais :) gérer_cast (msg, état) -> auto ()! {'$ Gen_cast', msg}, {noreply, état}.


Oui, j'ai considéré cela plus tôt. Très brièvement. ;) Votre première idée est une bonne. Le cas habituel est que j'ai besoin de collecter 8 articles avant de les traiter. Il y aura généralement 200 lots de ceux-ci dans un travail. J'essaie de calculer si votre méthode est plus efficace que de marquer chaque résultat avec un numéro et trier chaque lot une fois que 8 éléments ont été reçus.



3
votes

Peut-être que vous voulez vraiment utiliser gen_fsm. Ce comportement est généralement choisi des fronts choisi pour les protocoles, où le protocole dispose de certains états et de gérer les demandes différemment en fonction de l'état dans lequel il est actuellement.

Mais retour à Gen_Server, nous utilisons Gen_Server pour ses fonctionnalités. Il abonna aux événements système pour le chargement de code et vous donne le rappel Code_Change. Il provoque des rapports SASL sur des accidents. Vous obtenez une structure bien connue qui aide à la maintenance du code. Plus important encore, il implémente un protocole bien conçu pour les appels synchrones.

Il est difficile de dire que si les comportements OTP vous conviennent dans ce cas.


Compte tenu du commentaire, cela ressemble à un Gen_Server qui est faux pour vous. Lorsque j'utilise le comportement Gen_Server, j'en pense en tant que patron d'une entreprise. Tout le monde veut parler avec le patron, il est donc intéressé de rendre le patron capable de déléguer des emplois rapidement et efficacement afin qu'il ne laisse pas les gens assis attendre au lieu de travailler.

Le Gen_Server peut déléguer en utilisant le paramètre 'de'. Pour ce faire, retournez {no_reply, état} et transmettez le paramètre du délégué. Le délégué utilise gen_server: Répondre / 2 Pour répondre à l'appel d'origine.

Cette méthode d'utilisation d'un Gen_Server pourrait éventuellement être pour vous. Démarrez un processus «plain» que vous utilisez de la réception pour recevoir une réception sélective. S'il s'agit d'un travail vraiment indépendant, le Gen_Server peut l'ignorer (feu et oublier). Si elle veut savoir s'il est fini, on peut Gen_Server: Cast / 2 Un message à partir du processus "plain" démarré.

Si vous souhaitez bloquer le Gen_Server tout en effectuant le reçu sélectif, il pourrait s'agir d'une idée de démarrer un processus et d'attendre qu'il meure avant de revenir. Recevoir sélectif est une recherche linéaire O (N) sur les messages de l'ordre dans lequel ils sont arrivés. Donc, chaque réception sélective scannera tous les messages en file d'attente qui pourrait être élevé pour un Gen_Server populaire.

Aucune compagnie n'est censée seulement avoir des patrons qui y travaillent. Aucune application Erlang n'est supposée avoir uniquement Gen_Servers.


1 commentaires

Le Gen_FSM est une idée intéressante - je cherche une excuse pour l'utiliser. Au début rougeur, je ne pense pas que cela fonctionnera pour moi, à moins que je ne puisse "paramétrer" les états d'une manière ou d'une autre. Le cas typique est de 8 états, mais il y a des centaines de centaines. Je ne sais pas si Gen_fsm était conçu pour cela. Je veux vraiment vraiment que les fonctionnalités OTP, je vais donc gérer la réception sélective d'une autre manière que celle de Gen_serVers ne puisse apparemment pas le faire naturellement.



2
votes

Juste parce que vous ne pouvez pas utiliser Gen_Server pour que l'un de vos modules ne signifie pas que vous n'utilisez pas OTP. Tous les modules de rappel mettent en œuvre le bloc de réception pour vous qui vous empêche d'utiliser des reçus sélectifs. Il n'y a aucune raison pour laquelle vous ne pouvez pas implémenter votre propre service qui gère les reçus sélectifs. Et cela ne signifie pas que vous ne l'avez pas fait la voie OTP.

Vous pouvez toujours avoir votre service géré par un superviseur avec tous les avantages qui les permettent.


0 commentaires

4
votes

Non, Gen_Server n'est pas conçu pour pouvoir gérer les reçus sélectifs, chaque demande est traitée à l'arrivée. C'est en fait un problème difficile car Erlang nécessite que tous les modèles soient connus au moment de la compilation, il n'y a pas de "objet de motif".

Je suis d'accord que Gen_Fsm n'est probablement pas pour vous, que ce soit, car il ne faut pas que des messages différents qui arrivent dans n'importe quel ordre avant de passer une explosion dans le nombre d'états. C'était l'une des raisons pour lesquelles nous avons ajouté des reçus sélectifs, il vous permet d'ignorer en toute sécurité les messages inintéressants, de les laisser ultérieurement.

Quel OTP êtes-vous particulièrement intéressé?


2 commentaires

Si vous voulez dire quelles fonctionnalités OTP, eh bien, j'aime les trucs de débogage, comme Sys: get_status. Cela a déjà été vraiment pratique. Et les rapports d'accident qui viennent de SASL ont été inestimables. Et je veux que les processus soient supervisés, bien que cela soit peut-être aussi facile avec les processus ordinaires? Et j'ai un peu aimé l'idée d'appeler mes processus avec l'API Gen_Server. La plus grande chose est juste que c'est mon premier projet majeur Erlang et que c'est une date limite et un OTP semble être la bonne façon. Ne pas avoir le temps d'explorer tous les recoins, je veux m'assurer que je reçois tous les avantages intégrés.


C'est-à-dire que je veux me conformer autant que possible le cadre d'application afin que je puisse comprendre ce que sont les avantages. En outre, je n'ai pas encore à la manipulation de la mise à niveau de la libération et je m'attends à utiliser Gen_Servers pour cela.



7
votes

"plaine_fsm" vous permettra de recevoir une réception sélective tout en étant conforme à OTP.

http://github.com/esl/plain_fsm


0 commentaires