web-dev-qa-db-fra.com

Dask peut-il paralléliser la lecture d'un fichier csv?

Je convertis un gros fichier texte en un stockage hdf dans l'espoir d'un accès plus rapide aux données. La conversion fonctionne très bien, mais la lecture du fichier csv ne se fait pas en parallèle. Il est vraiment lent (prend environ 30 minutes pour un fichier texte de 1 Go sur un SSD, donc je suppose qu'il n'est pas lié aux E/S).

Existe-t-il un moyen de le lire dans plusieurs threads en parallèle? Bien que cela puisse être important, je suis actuellement obligé d'exécuter sous Windows - juste au cas où cela ferait une différence.

from dask import dataframe as ddf
df = ddf.read_csv("data/Measurements*.csv",
             sep=';', 
             parse_dates=["DATETIME"], 
             blocksize=1000000,
             )

df.categorize([ 'Type',
                'Condition',               
          ])

df.to_hdf("data/data.hdf", "Measurements", 'w')
17
Magellan88

Oui, dask.dataframe peut lire en parallèle. Cependant, vous rencontrez deux problèmes:

Pandas.read_csv ne libère que partiellement le GIL

Par défaut, dask.dataframe se parallélise avec les threads car la plupart des Pandas peuvent s'exécuter en parallèle dans plusieurs threads (libère le GIL). Pandas.read_csv est une exception, surtout si vos dataframes résultants utilisent des dtypes d'objet pour texte

dask.dataframe.to_hdf (nom de fichier) force le calcul séquentiel

L'écriture dans un seul fichier HDF forcera le calcul séquentiel (il est très difficile d'écrire dans un seul fichier en parallèle.)

Edit: Nouvelle solution

Aujourd'hui, j'éviterais HDF et utiliserais plutôt Parquet. J'utiliserais probablement les programmateurs multiprocessing ou dask.distributed pour éviter les problèmes GIL sur une seule machine. La combinaison de ces deux devrait vous donner une mise à l'échelle linéaire complète.

from dask.distributed import Client
client = Client()

df = dask.dataframe.read_csv(...)
df.to_parquet(...)

Solution

Étant donné que votre ensemble de données tient probablement en mémoire, utilisez dask.dataframe.read_csv pour charger en parallèle avec plusieurs processus, puis passez immédiatement à Pandas.

import dask.dataframe as ddf
import dask.multiprocessing

df = ddf.read_csv("data/Measurements*.csv",  # read in parallel
             sep=';', 
             parse_dates=["DATETIME"], 
             blocksize=1000000,
             )

df = df.compute(get=dask.multiprocessing.get)     # convert to pandas

df['Type'] = df['Type'].astype('category')
df['Condition'] = df['Condition'].astype('category')

df.to_hdf('data/data.hdf', 'Measurements', format='table', mode='w')
15
MRocklin

En vous basant sur la réponse de @ MRocklin, dans les nouvelles versions de dask, vous pouvez utiliser df.compute(scheduler='processes') ou df.compute(scheduler='threads') pour convertir en pandas en utilisant le multitraitement ou le multithreading:

from dask import dataframe as ddf
df = ddf.read_csv("data/Measurements*.csv",
             sep=';', 
             parse_dates=["DATETIME"], 
             blocksize=1000000,
             )

df = df.compute(scheduler='processes')     # convert to pandas

df['Type'] = df['Type'].astype('category')
df['Condition'] = df['Condition'].astype('category')

df.to_hdf('data/data.hdf', 'Measurements', format='table', mode='w')
6
mgoldwasser