【问题标题】:How to optimize writing a list of dictionaries using json dump into a file?如何优化使用 json 转储将字典列表写入文件?
【发布时间】:2021-11-16 04:51:53
【问题描述】:

目前我有以下实现将list 的dictionaries 写入文件。下面的file_limit_counter 将被初始化为0,而file_limit 现在将被初始化为50。因此,每当计数器等于文件限制时,它就会开始将输出写入新文件。计数器的方法是将输出分成多个文件:

self.file = self.generate_new_micro_file_name()
for response_dict in all_response_dict_list:
    if file_limit_counter == file_limit:
        self.propagate_log_msg('wrote {} records '.format(file_limit))
        self.file = self.generate_new_micro_file_name()
        file_limit_counter = 0
    with open(self.file, 'a', encoding="utf8") as open_out_file:
        json.dump(response_dict, open_out_file)
        open_out_file.write('\n')
    file_limit_counter += 1

列表all_response_dict_list 将包含如下内容:

somelist = [{"Name":"a1","Age":"24"},{"Name":"a2","Age":"26"}]

我的意图是在我的输出文件中包含这样的内容:

{"Name":"a1","Age":"24"}
{"Name":"a2","Age":"26"}
...

上述方法效果很好。但是,当涉及到大量词典(例如 5000)时,它往往会放慢一点(大约需要 10 分钟)。因此,如果有人已经遇到过这种情况,那将会很有帮助。我认为,如果我们可以并行执行上述相同的操作,即同时将多个字典写入同一个文件而不是一个一个地写入,我认为会花费更少的时间。

【问题讨论】:

  • 在这种情况下(我认为)工作管理器打开输出文件的方法是不合适的。每次打开同一个文件时,操作系统都必须先搜索到最后,然后才能将数据写入其中。所以,打开一次,当你达到限制时关闭它,然后打开你的下一个文件
  • 谢谢你@DarkKnight 你在那里。我也和你在同一页上,但只是大声说出来看看是否还有其他选择。
  • 按照 DarkKnight 的建议,我可以在 1.1 秒内写出 50,000 个名字。我会在下面发帖。
  • @TimRoberts 1.1s?你在用算盘吗;-)
  • 关闭,这是 Windows。打开和写入 1000 个文件需要一秒钟。

标签: python json python-3.x


【解决方案1】:

这通过保持文件打开而不是打开/关闭 50 次,在 1.1 秒内为 1,000 个文件处理 50,000 个名称。

import json
import time

# Generate.

part1 = time.time()

all_response_dict_list = []
for i in range(50000):
    all_response_dict_list.append( {'name':f'a{i}', 'age':str(i) } )

part2 = time.time()
print( part2 - part1 )

# Write.

file_limit = 50
file_limit_counter = 0
fnum = 0

def generate_new_micro_file_name():
    global fnum
    fnum += 1
    return f'base{fnum}.json'

open_out_file = open(generate_new_micro_file_name(), 'a', encoding='utf8')
for response_dict in all_response_dict_list:
    if file_limit_counter == file_limit:
        open_out_file = open(generate_new_micro_file_name(), 'a', encoding='utf8')
        file_limit_counter = 0
    json.dump(response_dict, open_out_file)
    open_out_file.write('\n')
    file_limit_counter += 1

print( time.time() - part2 )

【讨论】:

  • 您似乎没有关闭输出文件。它们可能不完整
  • 这似乎一次打开了所有 50000 个文件,这似乎很草率,在某些平台上可能是一个问题。无论如何,虽然这段代码可能会回答这个问题,但它可能会提供一些有限的即时帮助。 proper explanation 将通过说明为什么这是解决问题的好方法,将大大提高其长期价值,并使其对有其他类似问题的未来读者更有用。
  • 每个文件当然会在新文件打开后立即关闭,释放之前的引用。
  • @Tim:通过为变量分配新值来打开新文件并不一定会关闭之前的文件。
  • 在 CPython 中,绝对可以。在其他一些实现中,关闭可能会延迟到垃圾收集器运行后,但它们肯定会被关闭。
【解决方案2】:

您可以将列表拆分为 file_limit 大小的块,然后立即写入文件。

试试:

chunks = [all_response_dict_list[i: i+file_limit] for i in range(0, len(all_response_dict_list), file_limit)]

for chunk in chunks:
    with open(self.generate_new_micro_file_name()) as outfile:
        json.dump(chunk, outfile)

【讨论】:

    【解决方案3】:

    在我的机器上运行

    import json
    import time
    
    
    all_response_dict_list = [{'name': f'a{i}', 'age': i} for i in range(50_000)]
    file_limit = 50
    
    
    def fgen():
        fnum = 1
        while True:
            yield f'/Users/andy/j/base{fnum}.json'
            fnum += 1
    
    
    def main():
        G = fgen()
        for offset in range(0, len(all_response_dict_list), file_limit):
            with open(next(G), 'a') as outfile:
                for rd in all_response_dict_list[offset:offset+file_limit]:
                    json.dump(rd, outfile)
                    outfile.write('\n')
    
    
    if __name__ == '__main__':
        start = time.perf_counter()
        main()
        end = time.perf_counter()
        print(f'Duration={end-start:.4f}s')
    

    【讨论】:

    • 这与我的回答没有本质区别。
    • 除了它关闭文件句柄并在几乎一半的时间内运行
    • 您的代码在我的系统上运行的时间与我的完全相同。一旦打开新文件并删除旧引用,文件就会全部关闭。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    • 2013-06-07
    • 1970-01-01
    • 2014-06-30
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多