8
votes

Fonctions de liste d'entrelacement

permet de dire que je suis donné à deux fonctions: xxx

Je veux écrire une fonction équivalente de ceci: xxx

Mais quand je fais cela, pour les grandes listes inévitablement, je manquez de mémoire de mémoire.

Un exemple simple est le suivant: xxx

Je comprends cela est Le cas que la liste x est stockée en mémoire sans être recueillies. Ce serait mieux au lieu de F et g a fonctionné sur x dans, eh bien, "parallèle".

en supposant que je ne puisse pas changer f et g , ni de copier séparé de x (supposons < Code> x est cher à produire) Comment puis-je écrire h sans entrer dans des problèmes de mémoire?


1 commentaires

Je n'ai pas vraiment étudié cela auparavant, mais Scring.blogspot.com/2008/ 11 / Beau-pliing.html est directement sur point. Conal Elliot a également fait quelques suivi sur le sujet.


3 Réponses :


2
votes

Vous pouvez utiliser plusieurs threads pour évaluer fx et gx en parallèle.

par exemple par exemple xxx

sa Une bonne façon d'exploiter l'exécution parallèle de GHC pour empêcher une fuite d'espace en faisant deux choses à la fois.

Alternativement, vous devez fusionner f et g dans Un seul laissez-passer .


4 commentaires

Don: si somme est 10 fois plus rapide que produit , ne serait pas le produit retard derrière, empêcher la collecte des ordures et causer toujours une fuite d'espace? Cela pourrait fonctionner dans ce cas, mais dans le cas général, je peux le voir échouer.


Oui, ils doivent être approximativement à l'étape de verrouillage. Quand ils sont, vous avez ce qui ressemble à la fusion de boucle gratuitement (dynamiquement).


Don: Je ne suis pas sûr que cela fonctionne, je cherchais une solution générale qui n'entraînait pas à des horaires de processeurs différents susceptibles de causer des fuites d'espace.


Je dirais que cela ne fonctionnera que si la production de la liste est plus chère que les deux fonctions qui le consomment de manière à ce qu'ils courent à la fois à la même vitesse. Sinon, il semble que le risque d'une fuite d'espace soit trop élevé.



12
votes

Une réponse courte est que vous ne pouvez pas. Puisque vous n'avez pas de contrôle sur f et g , vous ne garantit aucune garantie que les fonctions traitent leur entrée séquentiellement. Une telle fonction peut aussi bien conserver toute la liste stockée dans la mémoire avant de produire le résultat final.

Toutefois, si vos fonctions sont exprimées en tant que pliures, la situation est différente. Cela signifie que nous savons comment appliquer progressivement chaque étape, afin que nous puissions parlementer ces étapes d'une course.

Les sont de nombreuses ressources sur cette zone. Par exemple:


0 commentaires

2
votes

Si vous pouvez transformer vos fonctions en plis, vous pouvez simplement les utiliser avec une analyse:

x = [1..100000000::Int] 
main = mapM_ print . tail . scanl foo (a0,b0) . takeWhile (not.null)  
         . unfoldr (Just . splitAt 1000)  -- adjust the chunk length as needed
         $ x

foo (a,b) x = let a2 = f' a $ f x ; b2 = g' b $ g x
              in a2 `seq` b2 `seq` (a2, b2)

f :: [t] -> a         -- e.g. sum
g :: [t] -> b         --      (`rem` 10007) . product
f' :: a -> a -> a     -- e.g. (+)
g' :: b -> b -> b     --      ((`rem` 10007) .) . (*)


0 commentaires