multitraitement en python de partage d'objets volumineux (par exemple, les pandas dataframe) entre plusieurs processus
Je suis à l'aide de Python multitraitement, plus précisément
from multiprocessing import Pool
p = Pool(15)
args = [(df, config1), (df, config2), ...] #list of args - df is the same object in each tuple
res = p.map_async(func, args) #func is some arbitrary function
p.close()
p.join()
Cette approche a une énorme consommation de mémoire; manger à peu près tous mes RAM (à quel point il devient extrêmement lent, ce qui rend le multitraitement assez inutile). Je suppose que le problème est que df
est un énorme objet (un grand pandas dataframe) et il est copié pour chaque processus. J'ai essayé d'utiliser multiprocessing.Value
de partager le dataframe sans copier
shared_df = multiprocessing.Value(pandas.DataFrame, df)
args = [(shared_df, config1), (shared_df, config2), ...]
(comme suggéré dans Python multiprocesseur à mémoire partagée), mais qui me donne TypeError: this type has no size
(le même que Le partage d'un objet complexe entre Python processus?, à laquelle malheureusement je ne comprends pas la réponse).
Je suis en utilisant le multitraitement pour la première fois et peut-être que ma compréhension n'est pas (encore) assez bon. Est multiprocessing.Value
en fait même la bonne chose à utiliser dans ce cas? J'ai vu d'autres suggestions (par exemple, la file d'attente), mais je suis un peu confus. Quelles options sont là pour partager de la mémoire, et qu'on serait mieux dans ce cas?
- voir plus récentes question: stackoverflow.com/questions/22468279/....
- Est-il un récent façon de le faire, ou est l'aide de
Namespace
la meilleure approche? Comment avez-vous atterri résoudre @Anne
Vous devez vous connecter pour publier un commentaire.
Le premier argument de
Value
est typecode_or_type. Qui est défini comme:C'est moi qui souligne. Donc, vous ne peut tout simplement pas mettre une pandas dataframe dans un
Value
, il doit être un ctypes type.Vous pouvez utiliser un
multiprocessing.Manager
de servir votre singleton dataframe exemple à l'ensemble de vos processus. Il y a différentes manières de se retrouver dans le même lieu - probablement le plus facile est de simplement plop votre dataframe dans le gestionnaire deNamespace
.Maintenant votre dataframe instance est accessible à tout processus qui est passée d'une référence à la Gestionnaire. Ou tout simplement passer une référence à la
Namespace
, c'est plus propre.Une chose que je n'ai pas/ne pas couvrir des événements et de signalisation - si votre processus de besoin d'attendre pour les autres à la fin de l'exécution, vous aurez besoin d'ajouter que, dans. Voici une page avec certains
Event
exemples qui couvrent un peu plus en détail comment utiliser le manager deNamespace
.(à noter qu'aucune de ces adresses si
multiprocessing
est le résultat tangible des avantages de performance, c'est juste de vous donner les outils pour explorer cette question)Namespace
approche entraîne une grande consommation de mémoire pour moi, trop. J'ai essayé cela avec un DF avec des millions de lignes et 6 colonnes (prise de 2 GO de RAM), et les travailleurs jusqu'à la fin avec ce sujet beaucoup de l'utilisation, trop. Qui plus est, l'accès aux données est rapide (< 1ms) lors de profilés non multitraitement devient vraiment lent pour le travailleur dans le multitraitement contexte. Même après la mem utilisation gonfle au travailleur, une seulens.df.loc[ix]
appel peut prendre plusieurs secondes. @roippi et @Jeff, avez-vous des idées à ce sujet?struct.error: 'i' format requires -2147483648 <= number <= 2147483647
", des suggestions? Est-il une autre technique?Vous pouvez partager une pandas dataframe entre les processus, sans surcharge de la mémoire par la création d'un data_handler processus enfant. Ce processus reçoit des appels de la part d'autres enfants avec les données spécifiques à la demande (c'est à dire une ligne, une cellule spécifique, une tranche etc..) à partir de votre très grande dataframe objet. Seul le data_handler processus maintient votre dataframe dans la mémoire à la différence d'un Gestionnaire comme espace de Noms qui provoque le dataframe à être copié à tous les processus enfants. Voir ci-dessous pour un exemple. Ce peut être converti à la piscine.
Besoin d'une barre de progression pour cela? voir ma réponse ici: https://stackoverflow.com/a/55305714/11186769