permet de dire que je suis donné à deux fonctions: Je veux écrire une fonction équivalente de ceci: p> Mais quand je fais cela, pour les grandes listes inévitablement, je manquez de mémoire de mémoire. P> Un exemple simple est le suivant: p> Je comprends cela est Le cas que la liste en supposant que je ne puisse pas changer x code> est stockée en mémoire sans être recueillies. Ce serait mieux au lieu de F code> et g code> a fonctionné sur x code> dans, eh bien, "parallèle". p> f code> et g code>, ni de copier séparé de x code> (supposons < Code> x code> est cher à produire) Comment puis-je écrire h code> sans entrer dans des problèmes de mémoire? p> p>
3 Réponses :
Vous pouvez utiliser plusieurs threads pour évaluer par exemple par exemple p> 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. P> Alternativement, vous devez fusionner fx code> et gx code> en parallèle. f code> et g code> dans Un seul laissez-passer . p> p>
Don: si somme code> est 10 fois plus rapide que produit code>, ne serait pas le produit code> 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é.
Une réponse courte est que vous ne pouvez pas. Puisque vous n'avez pas de contrôle sur 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. P> Les sont de nombreuses ressources sur cette zone. Par exemple: p> Le motif de consommation d'une séquence de valeurs avec des limites d'espace correctement définies est résolue plus généralement avec des bibliothèques comme des tuyaux tels conduit em>, itérats em> ou pipes em>. Par exemple, dans conduit em>, vous pouvez exprimer la combinaison des sommes informatiques et des produits comme p> f code> et g code>, 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.
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) .) . (*)
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.