python - 生成数百万的json数据

时间:2016-12-04 21:26:47

标签: python json out-of-memory pypy faker

我需要一些json格式的虚拟数据,以便在另一个项目中使用。我目前正在使用以下代码中的Faker包:

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,结果让我感到震惊。我现在能够在~600秒内生成一个包含100万个数据的json文件,大约220mb。问题是,当我试图进一步,例如,2百万数据,我希望它在~1200秒内完成,脚本运行超过这个时间,我受到这个异常MemoryError的欢迎,没有解释为什么它发生了,我相信它与PYPY_GC_MAX有关,但同样一个2M文件应该重约440mb。

在尝试解决这个问题的同时,我仍然在寻找一种方法来进一步缩短发电时间。我已经尝试了列表理解,map(),结果与循环相同。

由于

3 个答案:

答案 0 :(得分:1)

而不是output.write(json.dumps(database)),使用json.dump(database, output)迭代地将JSON写入文件而不在内存中构造大字符串。

答案 1 :(得分:1)

您不需要使用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."

答案 2 :(得分: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)])

结合Alex Hall的回答,这可以大大减少内存需求。

我不太了解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."