2016-12-04 17 views
0

Мне нужны некоторые фиктивные данные в формате json для использования в другом проекте. Я в настоящее время использую Faker пакет в коде ниже:python - генерация миллионов данных json

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." 

Этот код работает, но очень медленно. Я пробовал PyPy, и я был потрясен результатами. В настоящее время я могу создать json-файл с 1 миллионом данных, который составляет около 220 Мб, в ~ 600 секунд. Проблема заключается в том, что когда я пытаюсь перейти дальше, например, 2 миллиона данных, которые я ожидаю, что это закончится через ~ 1200 секунд, сценарий будет запущен за это время, и я приветствую это исключение MemoryError без объяснения причин произошло, я считаю, что у него есть что-то с PYPY_GC_MAX, но опять-таки 2M-файл должен весить ~ 440mb.

При попытке исправить эту проблему, я все еще ищу способ сжать время генерации еще больше. Я пробовал понимание списка, map(), результаты были такими же, как и для цикла.

Благодаря

+0

Какой питон вы используете? –

+0

Python 2.7.12 32bits – Be0wulf

+0

Вам нужно использовать 'OrderedDict'? Вероятно, это увеличивает время. –

ответ

0

Вы выходите из памяти, потому что сначала создаете всю базу данных, а затем выгружаете базу данных. Более удобным для памяти способом было бы генерировать записи dict на лету. Лучшим способом было бы использовать generator, который делает записи «на лету».

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)]) 

В сочетании с ответом Алекса Холла это должно значительно уменьшить потребность в памяти.

Я не знаю JSon-модуль так хорошо, но письмо было бы что-то вроде:

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

вы не 't передайте генератор напрямую, но перейдем к нему. Расширение на нем в моем ответе. –

+0

Текущий код OP создает массив JSON, поэтому это приведет к созданию объявления (хотя, по общему признанию, эта форма может быть лучшим способом).Чтобы создать список, вы могли бы, например, вручную писать в дополнительных запятых и квадратных скобках. –

+0

Спасибо [результат] (http://i.imgur.com/27tcRWB.png) – Be0wulf

1

Вместо output.write(json.dumps(database)), используйте json.dump(database, output) итеративно написать JSON в файл без построения большой строки в памяти.

+0

Это немного ускорило время генерации. Я попробую сейчас с 2M. – Be0wulf

+0

:('MemoryError' [Изображение] (http://i.imgur.com/lM4TxgC.png) из диспетчера задач до исключения. – Be0wulf

+0

@ Be0wulf проблема на этом этапе - это не JSON, а гигантский список! См. ответ Маартен и мой комментарий. –

0

Вам не нужно использовать OrderedDict: формат JSON не может (и не будет) сохранить порядок предметов. Даже если заказ будет сохранен в файле - он сломается, когда другой проект проанализирует этот файл.

Вам просто нужно использовать dict. И это будет намного быстрее.

Чтобы сохранить порядок элементов, вы должны явно сохранить индекс каждого элемента. Например:

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

Я знаю, что заказ не сохранен, так как я должен начинать с нуля, чтобы облегчить себе жизнь, я исправил заказ для использования своего шаблона. – Be0wulf