2016-12-04 2 views
0

Ich brauche einige Dummy-Daten im JSON-Format, um sie in einem anderen Projekt zu verwenden. Ich verwende derzeit das Faker Paket in dem folgenden Code:Python - Generierung von Millionen von JSON-Daten

from json import dumps 
from faker import Faker 
import collections 

database = [] 
filename = '1M' 
length = 1000000 
fake  = Faker() # <--- Forgot this 

for x in range(length): 
    database.append(collections.OrderedDict([ 
     ('last_name', fake.last_name()), 
     ('first_name', fake.first_name()), 
     ('street_address', fake.street_address()), 
     ('email', fake.email()) 
    ])) 

with open('%s.json' % filename, 'w') as output: 
    output.write(dumps(database, indent=4)) 
print "Done." 

Dieser Code funktioniert, aber es ist sehr langsam. Ich versuchte PyPy, und ich war von den Ergebnissen hin und weg. Ich bin derzeit in der Lage, eine JSON-Datei mit 1 Million Daten, die etwa 220 MB ist, in ~ 600 Sekunden zu generieren. Das Problem ist, wenn ich versuche, weiter zu gehen, zum Beispiel 2 Millionen Daten, die ich erwarten würde, dass es in ~ 1200 Sekunden endet, läuft das Skript über diese Zeit hinaus und ich werde von dieser Ausnahme MemoryError ohne Erklärung warum es begrüßt aufgetreten, ich glaube, es hat etwas mit PYPY_GC_MAX, aber wieder sollte eine 2M Datei ~ 440mb Gewicht.

Während ich versuche, dieses Problem zu beheben, suche ich immer noch einen Weg, die Generationszeit noch mehr zu drücken. Ich habe versucht, Liste Verständnis, map(), die Ergebnisse waren die gleichen wie für die Schleife.

Dank

+0

Welchen Python benutzen Sie? –

+0

Python 2.7.12 32bits – Be0wulf

+0

Benötigen Sie ein 'OrderedDict'? Das erhöht wahrscheinlich die Zeit. –

Antwort

0

Sie gehen aus dem Speicher, da Sie zunächst die gesamte Datenbank zuerst erstellen und dann die Datenbank ausgeben. Ein mehr speicherfreundlicher Weg wäre, die dict-Einträge im laufenden Betrieb zu erzeugen. Ein besserer Weg wäre die Verwendung eines generator, der die Einträge im laufenden Betrieb erstellt.

def fake_person_generator(length): 
    for x in range(length): # xrange in Python 2.7 
     yield OrderedDict([ 
      ('last_name', 'lastname_%i' % x), 
      ('first_name', 'firstname_%i' % x), 
      ('street_address', 'adress_%i' % x), 
      ('email', 'email_%i' % x)]) 

Kombiniert mit Alex Halls Antwort sollte dies den Speicherbedarf dramatisch reduzieren.

ich so gut das json-Modul weiß es nicht, aber das Schreiben so etwas wie wäre:

length = 1000000 
fpg = fake_person_generator(length) 
with open('%s.json' % filename, 'w') as output: 
    for person in fpg: 
     json.dump(person, output) 
print "Done." 
+0

Sie don Übergeben Sie den Generator nicht direkt, sondern iterieren Sie darüber. Erweitert in meiner Antwort. –

+0

Der aktuelle Code von OP erzeugt ein JSON-Array, also wird dies eine Anzeige erzeugen andere Ausgabe (obwohl zugegebenermaßen diese Form der bessere Weg sein könnte).Um eine Liste zu erstellen, könnten Sie beispielsweise manuell zusätzliche Kommas und eckige Klammern schreiben. –

+0

Danke [Ergebnis] (http://i.imgur.com/27tcRWB.png) – Be0wulf

1

Statt output.write(json.dumps(database)) verwenden json.dump(database, output) iterativ die JSON zu schreiben, ohne die Konstruktion eine große Zeichenfolge im Speicher abzulegen.

+0

Es steigerte die Generierung Zeit leicht. Ich werde es jetzt mit 2M versuchen. – Be0wulf

+0

:('MemoryError' [Bild] (http://i.imgur.com/lM4TxgC.png) vom Task-Manager vor der Ausnahme – Be0wulf

+0

@ Be0wulf das Problem in diesem Stadium ist nicht die JSON, aber die riesige Liste! Siehe Maartens Antwort und mein Kommentar. –

0

Sie OrderedDict nicht benutzen müssen: (und nicht) JSON-Format kann nicht speichern, um von Gegenständen. Selbst wenn die Reihenfolge in der Datei gespeichert wird, wird sie unterbrochen, wenn ein anderes Projekt diese Datei analysiert.

Sie müssen nur dict verwenden. Auch wird es viel schneller sein.

Um die Reihenfolge der Elemente zu speichern, sollten Sie explizit den Index eines jeden Elements beibehalten. Gefällt mir:

from json import dumps 
from faker import Faker 
import collections 
import json 

def fake_person_generator(length, fake): 
    for x in range(length): # xrange in Python 2.7 
     yield {'last_name': fake.last_name(), 
       'first_name': fake.first_name(), 
       'street_address': fake.street_address(), 
       'email': fake.email(), 
       'index': x} 

database = [] 
filename = '1M' 
length = 1000000 
fake  = Faker() # <--- Forgot this 
fpg = fake_person_generator(length, fake) 
with open('%s.json' % filename, 'w') as output: 
    output.write('[') # to made json file valid according to JSON format 
    for person in fpg: 
     json.dump(person, output) 
    output.write(']') # to made json file valid according to JSON format 
print "Done." 
+0

Ich bin mir bewusst, dass die Reihenfolge nicht eingehalten wird, da ich von Grund auf neu beginnen muss, um mein Leben einfacher zu machen, habe ich die Bestellung behoben eine Art Vorlage zu verwenden. – Be0wulf