2012-10-16 3 views
3

J'ai un tas de fichiers XML que je suis en train de traiter en parallèle. Mon code scala (2.9.2) en utilisant le futur commence bien mais finit par manger près de 100% du 32G que j'ai sur ma machine. Cela ne se produit pas lorsque je fais cela séquentiellement, donc je suppose qu'il y a quelque chose qui ne va pas avec la collecte des ordures dans l'utilisation de futures scala.Garbage collection avec Scala avenir

Voici une version allégée de mon code. Quelqu'un peut-il me dire ce qui ne va pas? ETA: Ok, j'ai résolu ceci mais je n'ai toujours aucune idée pourquoi cela fait une différence.

J'ai extrait la majeure partie du code dans les boucles internes, puis l'ai redécoupé. Et a sorti l'instanciation de l'analyseur du futur. L'utilisation de la mémoire reste stable à 17%. Quelqu'un a-t-il une idée de la raison pour laquelle cela ferait une différence?

est ici une version simplifiée de ce que je faisais:

def process(arglist...) = yada 

val tasks = filenameGroups.map { 
    fg => 
    val parser = new nu.xom.Builder() 
    scala.actors.Futures.future { 
     process(fg, parser) 
    } 
} 

val pairs = tasks.par.flatMap(_.apply) 
+0

Combien de fichiers souhaitez-vous traiter simultanément? Il semble que vous en ayez au moins des milliers. Le chargement de milliers de fichiers XML en mémoire entraînera rapidement la perte de toute votre RAM. Faire cela séquentiellement lit essentiellement le fichier, le traite et il est éligible pour la récupération de place. –

+0

@TomaszNurkiewicz Je veux traiter autant que possible et j'ai 200K fichiers. J'ai juste supposé que les futures de scala seraient intelligents et créeraient seulement 8 (ou peu de processeurs que vous ayez) les futures instances donc je n'ai que 8 docs xml en mémoire à la fois. – JasonMond

Répondre

2

Futures ne peut pas vraiment prédire le nombre de threads que vous voulez ou la quantité de mémoire calculs prendra, il est donc généralement votre responsabilité de mettre les calculs de manière appropriée sérialisés à l'intérieur d'un nombre modeste d'avenir. En particulier, si vous utilisez une machine à 8 cœurs, vous ne voulez probablement pas grouper beaucoup plus petit que someStringListOfFilepaths.length/8 (moins si vos fichiers sont si gros que vous ne pouvez pas avoir 8 en mémoire à la fois). Vous pouvez utiliser l'astuce Java standard pour inspecter le nombre de cœurs, covered on SO et bien d'autres endroits, si vous voulez l'adapter à chaque machine sans avoir à y penser. (Pourrait également inspecter Runtime.getRuntime.maxMemory dans le cas où vous êtes sur une machine avec beaucoup de cœurs et pas beaucoup de RAM (ou pas beaucoup allouée pour la VM).)

(Incidemment, dans votre exemple minimal il y a à la fois de la paresse et de l'avenir, mais la paresse ne fait rien pour vous.) Les contrats à terme ne sont déjà pas exécutés, donc retarder l'instanciation des futurs ne vous aidera probablement pas.)

vous avez 200k fichiers, vous obtiendrez 200k résultats, et en fonction de la taille d'un résultat, cela pourrait vous faire perdre beaucoup de mémoire. Probablement pas 32G, mais qui sait ce qu'il y a dans les fichiers?

+0

J'ai exécuté ce code séquentiellement et il n'a jamais atteint plus de 5% d'utilisation de la mémoire. Aussi, à votre recommandation, j'ai essayé d'augmenter la taille du groupe à 30K. Il finit toujours par atteindre presque 100% d'utilisation de la mémoire. – JasonMond

+0

@JasonMond - Que se passe-t-il si vous exécutez tous les fichiers dans un groupe? C'est, et si c'est séquentiel après tout mais juste enveloppé dans un futur? Je me demande si la chose parallèle et les contrats à terme est un faux-fuyant, et c'est en fait quelque chose à propos de votre fg.map avec un flux groupé? –

+1

N'est-ce pas Stream est mémoized et il garde une référence à la tête (tâches) –