J'ai essayé de signaler un bug que je rencontrais dans mclapply en ce qui concerne les grandes valeurs de retour n'étant pas autorisés.Réduction du temps système avec des fonctions parallèles dans R
Apparemment, le bug a été corrigé dans les versions de développement, mais je suis plus intéressé par le commentaire que le répondeur fait:
il y avait une limite de 2 Go la taille des objets sérialisés qui par exemple mclapply peut renvoyer à partir des processus fourchus et cet exemple tente 16GB. Cela a été levé (pour les versions 64 bits) dans R-devel, mais cette utilisation est très inhabituel et plutôt inefficace (l'exemple a besoin ca 150Go à cause de toutes les copies impliqués dans (un) sérialisation)
Si utiliser mclapply pour faire des calculs parallèles avec de grandes données est inefficace, alors quelle est la meilleure façon de le faire? Mon besoin de faire ce genre de chose ne fait qu'augmenter, et je suis en train de rencontrer des goulots d'étranglement partout. Les tutoriels que j'ai vus ont été des introductions assez simples sur la façon d'utiliser les fonctions, mais pas nécessairement comment utiliser efficacement les fonctions dans la gestion des compromis. La documentation a un petit texte de présentation sur ce compromis:
mc.preschedule: si réglé sur « TRUE », alors le calcul est d'abord divisé à (au plus) que de nombreux emplois sont là sont des noyaux et la des travaux sont démarrés, chaque travail couvrant éventuellement plus d'une valeur . Si la valeur est "FALSE", alors un travail est forké pour chaque valeur de 'X'. Le premier est meilleur pour les calculs courts ou grand nombre de valeurs dans 'X', ce dernier est meilleur pour les emplois qui ont une variance élevée de temps d'achèvement et pas trop de valeurs de 'X' par rapport à 'mc.cores'
et
Par défaut (« mc.preschedule = TRUE ») dont l'entrée « X » est divisé en autant de parties qu'il y a actuellement noyaux (les valeurs sont réparties pour les noyaux séquentiellement , c.-à-d. première valeur au noyau 1, deuxième au noyau 2 , ... (core + 1) -th valeur au core 1, etc.) puis un processus est fourchu à chaque cœur et les résultats sont collectés.
Sans pré-ordonnancement, un travail séparé est généré pour chaque valeur de 'X'. Pour vous assurer que pas plus les emplois »mc.cores de sont en cours d'exécution à une fois, une fois ce nombre a été fourchue le processus maître attend pour un enfant de terminer avant la prochaine fourche
Benchmarking ces choses se fiable une beaucoup de temps car certains problèmes ne se manifestent qu'à grande échelle, et il est alors difficile de comprendre ce qui se passe. Donc, avoir un meilleur aperçu du comportement des fonctions serait utile.
modifier:
Je n'ai pas un exemple précis, parce que j'utilise mclapply beaucoup et je voulais mieux savoir comment réfléchir sur les implications de performance. Et pendant que j'écris sur le disque, je contournerais l'erreur, je ne pense pas que cela aiderait en ce qui concerne la (dé) sérialisation qui doit se produire, qui devrait également passer par le disque IO.
Un flux de travail serait la suivante: Prenez une grande matrice clairsemée M
, et l'écrire sur le disque en morceaux (par exemple M1-M100
) parce que M lui-même ne correspond pas à la mémoire.
dire maintenant, pour chaque utilisateur i
dans I
il y a Ci
colonnes M
que je veux ajouter et globale au niveau de l'utilisateur. Avec des données plus petites, ce serait relativement trivial:
m = matrix(runif(25), ncol=5)
df = data.frame(I=sample(1:6, 20, replace=T), C=sample(1:5, 20, replace=T))
somefun = function(m) rowSums(m)
res = sapply(sort(unique(df$I)), function(i) somefun(m[,df[df$I == i,]$C]))
Mais avec des données plus importantes, mon approche était de diviser le data.frame d'utilisateur/colonnes dans différentes data.frames sur la base duquel la matrice M1-M100
la colonne serait , faites une boucle parallèle sur ces data.frames, lisez dans la matrice associée, puis bouclez sur les utilisateurs, en extrayant les colonnes et en appliquant ma fonction, puis en prenant la liste de sortie, et en bouclant à nouveau et en réagrégeant. Ce n'est pas idéal si j'ai une fonction qui ne peut pas être réagrégée comme ça (pour l'instant, ce n'est pas un problème), mais je suis apparemment en train de mélanger trop de données avec cette approche.
Sans connaître la structure de votre problème, il est difficile de dire comment vous pourriez faire mieux. J'ai regardé votre exemple dans le rapport de bug et c'est probablement juste pour démontrer que vous ne pouviez pas retourner de gros objets. Vous pourriez vouloir regarder dans les paquets de mémoire partagée.Vous devez afficher un exemple minimal reproductible qui capture la structure de votre problème, tout en étant assez simple à comprendre. Je ne pense pas que la planification des tâches (comme dans 'mc.preschedule') vous mènera partout. – cryo111
J'ai posté un exemple simple de ce que je fais, mais les complications viennent de tout ce qui se passe avec les E/S du disque, la sérialisation et de tels problèmes. Est ce que j'essaye de faire clair? – James