2015-01-02 18 views
8

Zrobiłem trochę przypadek testowy porównać YAML i JSON prędkość:Czy mogę przyspieszyć YAML?

import json 
import yaml 
from datetime import datetime 
from random import randint 

NB_ROW=1024 

print 'Does yaml is using libyaml ? ',yaml.__with_libyaml__ and 'yes' or 'no' 

dummy_data = [ { 'dummy_key_A_%s' % i: i, 'dummy_key_B_%s' % i: i } for i in xrange(NB_ROW) ] 


with open('perf_json_yaml.yaml','w') as fh: 
    t1 = datetime.now() 
    yaml.safe_dump(dummy_data, fh, encoding='utf-8', default_flow_style=False) 
    t2 = datetime.now() 
    dty = (t2 - t1).total_seconds() 
    print 'Dumping %s row into a yaml file : %s' % (NB_ROW,dty) 

with open('perf_json_yaml.json','w') as fh: 
    t1 = datetime.now() 
    json.dump(dummy_data,fh) 
    t2 = datetime.now() 
    dtj = (t2 - t1).total_seconds() 
    print 'Dumping %s row into a json file : %s' % (NB_ROW,dtj) 

print "json is %dx faster for dumping" % (dty/dtj) 

with open('perf_json_yaml.yaml') as fh: 
    t1 = datetime.now() 
    data = yaml.safe_load(fh) 
    t2 = datetime.now() 
    dty = (t2 - t1).total_seconds() 
    print 'Loading %s row from a yaml file : %s' % (NB_ROW,dty) 

with open('perf_json_yaml.json') as fh: 
    t1 = datetime.now() 
    data = json.load(fh) 
    t2 = datetime.now() 
    dtj = (t2 - t1).total_seconds() 
    print 'Loading %s row into from json file : %s' % (NB_ROW,dtj) 

print "json is %dx faster for loading" % (dty/dtj) 

a wynik jest:

Does yaml is using libyaml ? yes 
Dumping 1024 row into a yaml file : 0.251139 
Dumping 1024 row into a json file : 0.007725 
json is 32x faster for dumping 
Loading 1024 row from a yaml file : 0.401224 
Loading 1024 row into from json file : 0.001793 
json is 223x faster for loading 

Używam PyYAML 3.11 z libyaml biblioteki C na Ubuntu 12.04. Wiem, że json jest znacznie prostszy niż yaml, ale przy stosunku 223x pomiędzy jsonem i yaml zastanawiam się, czy moja konfiguracja jest poprawna czy nie.

Czy masz taki sam współczynnik prędkości?
Jak mogę przyspieszyć yaml.load()?

Odpowiedz

12

Zapewne zauważyłeś, że składnia Pythona dla struktur danych to bardzo podobnie do składni JSON.

Co się dzieje jest json biblioteka Pythona koduje wbudowane typy danych Pythona directly into text chunks, zastępując ' do " i usuwanie , tu i tam (do oversimplify trochę).

Z drugiej strony, pyyaml ma przed serializowaniem go na łańcuch.

Ten sam rodzaj rzeczy musi się zdarzyć podczas ładowania.

Jedynym sposobem na przyspieszenie yaml.load() byłoby napisać nową Loader, ale wątpię, to może być to ogromny skok w wydajności, z wyjątkiem, jeśli jesteś gotów do pisania własnych jednofunkcyjnych sort-YAML parsera, biorąc the following comment w zamian:

YAML buduje wykres ponieważ jest ogólnego przeznaczenia Formatowanie serializacji że jest w stanie reprezentować wiele odniesień do tego samego obiektu. Jeśli wiesz, że żaden obiekt nie jest powtarzany i pojawiają się tylko podstawowe typy, możesz użyć serializatora json, ale nadal będzie to poprawny YAML.

- UPDATE

Co powiedziałem wcześniej pozostaje prawdą, ale jeśli używasz Linux istnieje sposób, aby przyspieszyć Yaml analizowania. Domyślnie Python yaml używa parsera Python. Musisz powiedzieć, że chcesz użyć parsera PyYamlC.

Można zrobić to w ten sposób:

import yaml 
from yaml import CLoader as Loader, CDumper as Dumper 

dump = yaml.dump(dummy_data, fh, encoding='utf-8', default_flow_style=False, Dumper=Dumper) 
data = yaml.load(fh, Loader=Loader) 

Aby to zrobić, trzeba yaml-cpp-dev zainstalowany, na przykład za pomocą apt-get:

$ apt-get install yaml-cpp-dev 

And PyYaml z LibYaml również. Ale tak już jest w przypadku twojego wyjścia.

Nie mogę tego przetestować teraz, ponieważ korzystam z OS X i brew ma problemy z instalacją yaml-cpp-dev, ale jeśli podążasz za PyYaml documentation, są całkiem jasne, że wydajność będzie znacznie lepsza.

+1

ładowanie jest nadal 12 razy wolniejsze z przykładem yaml.my to lista 600 000 pustych słowników. Yaml nie musi robić nic więcej oprócz nieco sprytniejszej analizy składni, która nie powinna zajmować prawie żadnego dodatkowego czasu. – codeshot

+1

Na Macu: napar zainstalować yaml-cpp libyaml –

+0

Jivan jesteś krwawą legendą. Miałem zamiar przepisać trochę kodu Pythona w C++, aby przyspieszyć działanie. Mój plik yaml o wielkości 6 MB zajął 53 sekundy, aby załadować go za pomocą standardowego programu ładującego yaml, a tylko 3 sekundy za pomocą programu CLoader. – nevelis

0

Tak, zauważyłem również, że JSON jest znacznie szybszy. Więc rozsądnym podejściem byłoby najpierw przekonwertować YAML na JSON. Jeśli nie przeszkadza rubin, to można dostać duże przyspieszenie i rów yaml zainstalować łącznie:

import commands, json 
def load_yaml_file(fn): 
    ruby = "puts YAML.load_file('%s').to_json" % fn 
    j = commands.getstatusoutput('ruby -ryaml -rjson -e "%s"' % ruby) 
    return json.loads(j[1]) 

Oto porównanie do 100K rekordów:

load_yaml_file: 0.95 s 
yaml.load: 7.53 s 

I 1M rekordów:

load_yaml_file: 11.55 s 
yaml.load: 77.08 s 

Jeśli nalegasz na używanie yaml.load i tak, pamiętaj o umieszczeniu go w virtualenv, aby uniknąć konfliktów z innym oprogramowaniem.