Python多线程 - 写入文件慢10倍

时间:2015-09-18 18:23:47

标签: python multithreading

我一直在尝试将包含多行(270亿)的大型文件转换为JSON。 Google Compute建议我利用多线程来改善写入时间。我已将此代码转换为:

import json
import progressbar
f = open('output.txt', 'r')
r = open('json.txt', 'w')
import math
num_permutations = (math.factorial(124)/math.factorial((124-5)))
main_bar = progressbar.ProgressBar(maxval=num_permutations, \
widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage(), progressbar.AdaptiveETA()])
main_bar.start()
m = 0
for lines in f:
        x = lines[:-1].split(' ')
        x = json.dumps(x)
        x += '\n'
        r.write(x)
        m += 1
        main_bar.update(m)

到此:

import json
import progressbar
from Queue import Queue
import threading
q = Queue(maxsize=5)
def worker():
        while True:
                task = q.get()
                r.write(task)
                q.task_done()
for i in range(4):
        t = threading.Thread(target=worker)
        t.daemon = True
        t.start()
f = open('output.txt', 'r')
r = open('teams.txt', 'w')
import math
num_permutations = (math.factorial(124)/math.factorial((124-5)))
main_bar = progressbar.ProgressBar(maxval=num_permutations, \
widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage(), progressbar.AdaptiveETA()])
main_bar.start()
m = 0
for lines in f:
        x = lines[:-1].split(' ')
        x = json.dumps(x)
        x += '\n'
        q.put(x)
        m += 1
        main_bar.update(m)

我已经从模块手册中直接复制了Queue编码。

之前,整个脚本需要2天。现在说20天了!我不太清楚为什么,有人可以向我解释这个吗?

编辑:这可以被认为是一个Python全局解释器锁(GIL)问题,但是,我认为不是这样 - 它不是计算密集型的,并且是一个IO瓶颈问题,来自线程文档:

  

如果您希望您的应用程序更好地利用计算   多核机器的资源,建议你使用   多。但是,线程仍然是一个合适的模型   您希望同时运行多个I / O绑定任务。

我对此的理解是有限的,但我相信这是后者,即。 IO绑定任务。这是我最初的想法,当我想首先进行多线程时:计算被IO调用阻止,可以将其放到一个单独的线程中以允许计算功能继续。

进一步编辑:也许事实是我从INPUT获得了一个IO块,这就是减慢它的速度。关于如何有效地将'for'循环发送到单独的线程的任何想法?谢谢!

1 个答案:

答案 0 :(得分:1)

如果你想加快速度,根本不使用Python - 任务很简单,可以处理Unix过滤器,例如:

sed 's/ /", "/g; s/^/["/; s/$/"]/' output.txt > json.txt

有关其工作原理的说明,请参阅此处:https://stackoverflow.com/a/14427404/4323

如果您关心速度,使用Python的问题在于您从输入文件中一次从根本上读取一行。现在,你可以通过一些奇特的方式进行阅读(分而治之),但如果你只是想加快速度,那么上面应该可以解决问题。

如果你想要一个进度条,请使用pv(来自许多Linux系统上的软件包moreutils),我认为这会是这样的:

pv output.txt | sed 's/ /", "/g; s/^/["/; s/$/"]/' > json.txt