2010-04-19 5 views
5

J'ai un ensemble de points de données, chacun décrit par un dictionnaire. Le traitement de chaque point de données est indépendant et je soumets chacun d'eux en tant que travail séparé à un cluster. Chaque point de données a un nom unique et mon wrapper de soumission de cluster appelle simplement un script qui prend le nom d'un point de données et un fichier décrivant tous les points de données. Ce script accède alors au point de données du fichier et effectue le calcul. Comme chaque travail doit charger l'ensemble des points uniquement pour récupérer le point à exécuter, j'ai voulu optimiser cette étape en sérialisant le fichier décrivant l'ensemble des points dans un format facilement récupérable.Sérialisation JSON rapide (et comparaison avec Pickle) pour l'informatique en cluster en Python?

J'ai essayé d'utiliser JSONpickle, en utilisant la méthode suivante, pour sérialiser un dictionnaire décrivant tous les points de données dans le fichier:

def json_serialize(obj, filename, use_jsonpickle=True): 
    f = open(filename, 'w') 
    if use_jsonpickle: 
    import jsonpickle 
    json_obj = jsonpickle.encode(obj) 
    f.write(json_obj) 
    else: 
    simplejson.dump(obj, f, indent=1) 
    f.close() 

Le dictionnaire contient des objets très simples (listes, chaînes, flotteurs, etc.) et a un total de 54 000 touches. Le fichier json a une taille de ~ 20 mégaoctets.

Il faut ~ 20 secondes pour charger ce fichier en mémoire, ce qui me semble très lent. Je suis passé à utiliser pickle avec le même objet exact, et a constaté qu'il génère un fichier d'environ 7,8 mégaoctets de taille, et peut être chargé dans ~ 1-2 secondes. C'est une amélioration significative, mais il semble toujours que le chargement d'un petit objet (moins de 100 000 entrées) devrait être plus rapide. En dehors de cela, pickle n'est pas lisible par l'homme, ce qui était le gros avantage de JSON pour moi.

Existe-t-il un moyen d'utiliser JSON pour obtenir des accélérations similaires ou meilleures? Si non, avez-vous d'autres idées pour structurer cela?

(Est-ce que la bonne solution consiste simplement à "découper" le fichier décrivant chaque événement dans un fichier séparé et à le transmettre au script qui exécute un point de données dans un travail de cluster? Cela semble entraîner une prolifération de des dossiers).

merci.

Répondre

7

marshal est le plus rapide, mais pickle en tant que tel n'est pas - peut-être vous dire cPickle (ce qui est assez rapide, surtout avec un protocole -1.).Ainsi, en dehors des questions de lisibilité, voici un code pour montrer différentes possibilités:

import pickle 
import cPickle 
import marshal 
import json 

def maked(N=5400): 
    d = {} 
    for x in range(N): 
    k = 'key%d' % x 
    v = [x] * 5 
    d[k] = v 
    return d 
d = maked() 

def marsh(): 
    return marshal.dumps(d) 

def pick(): 
    return pickle.dumps(d) 

def pick1(): 
    return pickle.dumps(d, -1) 

def cpick(): 
    return cPickle.dumps(d) 

def cpick1(): 
    return cPickle.dumps(d, -1) 

def jso(): 
    return json.dumps(d) 

def rep(): 
    return repr(d) 

et voici leur vitesse sur mon ordinateur portable:

$ py26 -mtimeit -s'import pik' 'pik.marsh()' 
1000 loops, best of 3: 1.56 msec per loop 
$ py26 -mtimeit -s'import pik' 'pik.pick()' 
10 loops, best of 3: 173 msec per loop 
$ py26 -mtimeit -s'import pik' 'pik.pick1()' 
10 loops, best of 3: 241 msec per loop 
$ py26 -mtimeit -s'import pik' 'pik.cpick()' 
10 loops, best of 3: 21.8 msec per loop 
$ py26 -mtimeit -s'import pik' 'pik.cpick1()' 
100 loops, best of 3: 10 msec per loop 
$ py26 -mtimeit -s'import pik' 'pik.jso()' 
10 loops, best of 3: 138 msec per loop 
$ py26 -mtimeit -s'import pik' 'pik.rep()' 
100 loops, best of 3: 13.1 msec per loop 

, vous pouvez avoir la lisibilité et dix fois les vitesse de json.dumps avec repr (vous sacrifier la facilité de l'analyse de Javascript et d'autres langues); vous pouvez avoir la vitesse maximale absolue avec marshal, presque 90 fois plus vite que json; cPickle offre beaucoup plus de généralité (en termes de ce que vous pouvez sérialiser) que json ou marshal, mais si vous n'utilisez jamais cette généralité alors vous pouvez aussi bien opter pour marshal (ou repr si la lisibilité humaine l'emporte sur la vitesse). En ce qui concerne votre idée de "découpage", au lieu d'une multitude de fichiers, vous pourriez envisager une base de données (une multitude d'enregistrements) - vous pourriez même vous en passer sans sérialisation réelle si vous utilisez des données qui a un "schéma" reconnaissable.

+0

Merci beaucoup pour votre réponse informative, qui a été très utile. Quelles bases de données recommanderiez-vous en python? Je préférerais beaucoup les choses qui ne nécessitent pas de serveurs de base de données autonomes - ou mieux encore qui sont intégrés à python, peut-être comme sqlite - par rapport à ceux qui le font. Des pensées à ce sujet? Est-ce qu'une approche de base de données dans Python rivaliserait avec les temps de pickle pour le cas de test d'un dictionnaire pour ~ 50 000 clés où vous devez découper une entrée particulière? Si je passe à une base de données, je vais écrire du code personnalisé pour sérialiser en CSV afin que mes fichiers puissent être partagés et lus par d'autres utilisateurs humains. – user248237dfsf

+0

Si vous utilisez un DB incorporé, sqlite est le meilleur, mais comme tout autre DB incorporé, il n'achète aucun traitement parallèle, la grande force de performance de l'approche DB dans ce cas. Est-ce difficile d'exécuter un processus PostgreSQL, après tout? Et maintenant, vous obtenez une parfaite parallélisation de l'accès aux données et une grande amélioration des performances. (L'écriture de CSV ou d'autres formes dans une base de données SQL, et le retour du contenu de la base de données à n'importe quel type de tâche est un travail facile avec des scripts auxiliaires simples, bien sûr indépendants du moteur DB choisi). –

1

Je pense que vous faites face à un compromis ici: la lisibilité humaine se fait au détriment de la performance et de la taille de fichier importante. Ainsi, de toutes les méthodes de sérialisation disponibles en Python, JSON n'est pas seulement le plus lisible, c'est aussi le plus lent.

Si je devais poursuivre la performance (et la compacité du fichier), je dirais marshall. Vous pouvez soit rassembler l'ensemble avec dump() et load() ou, en construisant sur votre idée de trancher les choses, marshal séparer les parties de l'ensemble de données dans des fichiers distincts. De cette façon, vous ouvrez la porte à la parallélisation du traitement des données - si vous vous sentez si enclin.

Bien sûr, il existe toutes sortes de restrictions et d'avertissements dans la documentation, donc si vous décidez de jouer en toute sécurité, optez pour pickle.

+0

JSON est plus lent que XML? Cela ne semble pas juste ... –

Questions connexes