10
votes

Comment les énumérateurs travaillent-ils dans Ruby 1.9.1?

Cette question ne concerne pas comment utiliser des énumérateurs dans Ruby 1.9.1, mais je suis plutôt curieux comment ils travaillent. Voici quelques codes: xxx

dans le code ci-dessus, je peux utiliser e = bunk.new.each , puis e.next , e.next Pour obtenir chaque élément successif, mais comment est-ce exactement la suspension d'exécution, puis la reprise au bon endroit?

Je suis conscient que si le rendement dans le 0UVETO est remplacé par fibre.yield , il est facile de comprendre, mais ce n'est pas le cas ici. C'est un vieil un clair , alors comment ça marche?

J'ai regardé Enumerator.c mais c'est un hostile sur incompréhensible pour moi. Peut-être que quelqu'un pourrait fournir une implémentation en rubis, en utilisant des fibres, pas 1,8,6 énumérateurs à base de continuation, qui rend tout ce qui est clair?


0 commentaires

4 Réponses :


4
votes

En fait dans votre e = bunk.New.ef.ach la clause de l'autre n'est pas exécutée initialement. Au lieu de cela, la clause "if! Block_given" exécute et renvoie un objet d'énumérateur. L'objet Enumerator conserve un objet de fibre interne. (Au moins c'est à quoi cela ressemble à Enumerator.c)

Lorsque vous appelez E.Ache, il appelle une méthode sur un énumérateur qui utilise une fibre interne pour suivre son contexte d'exécution. Cette méthode appelle le bunk.Chaque méthode à l'aide du contexte d'exécution des fibres. Le bunk.Chaque appel ici exécute la clause de l'autre et donne la valeur de la valeur.

Je ne sais pas comment le rendement est mis en œuvre ou comment une fibre suit le contexte d'exécution. Je n'ai pas regardé ce code. Presque tout l'énumérateur et la magie de fibres sont mises en œuvre dans c.

Vous demandez vraiment comment les fibres et le rendement sont mis en œuvre? Quel niveau de détail recherchez-vous?

Si je suis hors bas, corrigez-moi.


1 commentaires

Merci pour votre réponse. Oui, je demande beaucoup de détails à ce sujet. Spécifiquement, j'aimerais savoir s'il est possible de tout mettre en œuvre dans Ruby ou s'il y a quelque chose de sournois dans C qui n'est pas possible dans Ruby. S'il est possible de la mettre en œuvre purement en rubis, j'aimerais voir le code! :)



15
votes

Voici un énumérateur de rubis simple qui utilise des fibres et devrait plutôt bien se comporter comme l'original: xxx

et au cas où tout le monde se sent mal à l'emploi de l'utilisation d'exceptions pour le flux de contrôle: le véritable énumérateur augmente l'arrêt À la fin, aussi, donc je viens d'émuler le comportement d'origine.

Utilisation: xxx


0 commentaires

1
votes

Comme les autres affiches notées, je crois que cela crée sa propre "fibre" privée [en 1.9]. Dans 1.8.7 (ou 1.8.6 si vous utilisez la joyau BackPorts) d'une manière ou d'une autre, elle fait la même chose (peut-être parce que tous les threads de 1,8 sont l'équivalent des fibres, il les utilise simplement?)

Ainsi, dans les 1,9 et 1.8.x, si vous en portiez plusieurs d'entre eux ensemble aached_line.map.each_with_index {}

Il coule en fait à travers cette chaîne entière avec chaque ligne, comme un tuyau sur la ligne de commande

http://pragdave.blogs.pragprrog.com /pragdave/2007/12/pipelines-utilisation.html

hth.


1 commentaires

Voici une excellente description détaillée wiki.github.com/rdp/Ruby_Tutorials_core/enumerator



1
votes

Je pense que cela serait plus précis. Appeler chacun sur l'énumérateur doit être identique à celle d'appeler la méthode d'itérateur d'origine. Donc, je changerais légèrement la solution originale à ceci: xxx


0 commentaires