【问题标题】:How do I Convert Python Dict to JSON in a Multi-Threaded Fashion如何以多线程方式将 Python Dict 转换为 JSON
【发布时间】:2012-04-20 18:36:51
【问题描述】:

我有许多包含数千行 python dict 格式的大文件。我正在使用 json.dumps 将它们转换为 json 字符串。

import json
import ast

mydict = open('input', 'r')
output = open('output.json', "a")

for line in mydict:
        line = ast.literal_eval(line)
        line = json.dumps(line)
        output.write(line)
        output.write("\n")

这可以完美地工作,但是,它以单线程方式进行。有没有一种简单的方法可以利用系统中的剩余内核来加快速度?

编辑:

根据我在这里开始使用多处理库的建议:

import os
import json
import ast
from multiprocessing import Process, Pool

mydict = open('twosec.in', 'r')

def info(title):
        print title
        print 'module name:', __name__
        print 'parent process: ', os.getppid()
        print 'process id:', os.getpid()

def converter(name):
        info('converter function')
        output = open('twosec.out', "a")
        for line in mydict:
                line = ast.literal_eval(line)
                line = json.dumps(line)
                output.write(line)
                output.write("\n")

if __name__ == '__main__':
        info('main line')
        p = Process(target=converter, args=(mydict))
        p.start()
        p.join()

我不太明白 Pool 的作用是什么,你能解释一下吗?

【问题讨论】:

  • 这里的瓶颈可能是I/O,所以我怀疑你会从使用多线程进行转换中获得什么好处。

标签: python json


【解决方案1】:

我不知道有一种简单的方法可以让您从多线程中获得加速,但如果您确实想要任何类型的加速,那么我建议您尝试使用ujson 包而不是json。它为我带来了非常显着的加速,基本上是免费的。使用与使用常规 json 包相同的方式。

http://pypi.python.org/pypi/ujson/

【讨论】:

  • 这是一个相当快速的 json 模块:pushingtheweb.com/2011/03/…
  • 我确实看到了 ujson 的小改进,将 1.23 分钟的 200MB 转换缩短了大约 3 秒。然而,这只是 2TB 文件的 5 分钟节省“是的,有些文件那么大”
  • 对,那么我同意@poke 的观点,即这里的瓶颈可能是磁盘 IO,无论您为问题投入多少处理器或更好的算法,您都不会看到显着的改进。在这里提高速度的唯一方法是获得读取速度更快的硬盘驱动器,例如 SSD 或 RAID 配置。
【解决方案2】:

将上面的代码包装在一个函数中,该函数将文件名作为其单个参数,并将 json 写入输出文件。

然后从multiprocessing 模块创建一个Pool 对象,并使用Pool.map() 将您的函数并行应用于所有文件的列表。这将自动使用您 CPU 上的所有内核,并且由于它使用多个进程而不是线程,因此您不会遇到全局解释器锁。

编辑:像这样更改程序的主要部分;

  if __name__ == '__main__':
     files = ['first.in', 'second.in', 'third.in'] # et cetera
     info('main line')
     p = Pool()
     p.map(convertor, files)
     p.close()

当然,您还应该更改convertor() 以从输入名称派生输出名称!

以下是使用ImageMagick程序将DICOM文件转换为PNG格式的完整示例

"Convert DICOM files to PNG format, remove blank areas."

import os
import sys # voor argv.
import subprocess
from multiprocessing import Pool, Lock

def checkfor(args):
    try:
        subprocess.check_output(args, stderr=subprocess.STDOUT)
    except CalledProcessError:
        print "Required program '{}' not found! exiting.".format(progname)
        sys.exit(1)

def processfile(fname):
    size = '1574x2048'
    args = ['convert', fname, '-units', 'PixelsPerInch', '-density', '300', 
            '-crop', size+'+232+0', '-page', size+'+0+0', fname+'.png']
    rv = subprocess.call(args)
    globallock.acquire()
    if rv != 0:
        print "Error '{}' when processing file '{}'.".format(rv, fname)
    else:
        print "File '{}' processed.".format(fname)
    globallock.release()

## This is the main program ##
if __name__ == '__main__':
    if len(sys.argv) == 1:
        path, binary = os.path.split(sys.argv[0])
        print "Usage: {} [file ...]".format(binary)
        sys.exit(0)
    checkfor('convert')
    globallock = Lock()
    p = Pool()
    p.map(processfile, sys.argv[1:])
    p.close()

【讨论】:

  • 我已根据您的建议进行了编辑,但这只是一个开始,我仍然不确定在哪里/如何实施 Pool
  • 我已经尝试了一些“以上”的东西,但我似乎仍然无法让它工作。你能解释一下如何使用 Pool.map() 吗?
  • 我添加了一个脚本作为示例,用于并行转换图像。希望对你有帮助。请注意,默认情况下,Pool 只会创建与核心数量一样多的工作进程。如果您想要更多进程,则需要在创建池时告知这一点。请参阅文档。
猜你喜欢
  • 2019-10-08
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 2018-11-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-19
  • 1970-01-01
相关资源
最近更新 更多