2012-04-20 37 views
1

我有許多帶有數千行python dict格式的大文件。我使用json.dumps將它們轉換爲json字符串。如何以多線程的方式將Python字典轉換爲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() 

我不太明白的地方池進場時,你能解釋一下嗎?

+0

這裏的瓶頸可能是I/O,所以我懷疑你會得到什麼好處使用多個線程來執行*轉換*。 – poke 2012-04-20 18:40:44

回答

1

裹在作爲其單個參數的文件名和寫入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()從輸入名稱派生輸出的名字!

下面是一個程序,DICOM文件轉換成PNG格式的完整的例子,使用ImageMagick程序

"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() 
+0

我已根據您的建議進行了編輯,但這僅僅是一個開始,我仍然不確定在哪裏/如何實施Pool – secumind 2012-04-20 19:25:51

+0

我已經嘗試了幾個「上方」的東西,但我似乎仍然無法讓它工作。你能解釋一下如何使用Pool.map()嗎? – secumind 2012-04-20 23:48:02

+0

我作爲示例添加了一個用於並行轉換圖像的腳本。希望對你有幫助。請注意,默認情況下,池只會創建與核心數量相同的工作進程。如果你想要更多的進程,你需要告訴你當你創建池。請參閱文檔。 – 2012-04-21 10:41:51

1

我不知道一個簡單的方法讓你從多線程獲得加速,但是如果任何類型的加速確實是你想要的,那麼我會建議嘗試使用ujson包而不是json。它爲我提供了非常顯着的加速,基本上免費。按照使用常規json包的方式使用它。

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

+0

這是一個相當快速的json模塊:http://pushingtheweb.com/2011/03/ultra-fast-json-encoding-decoding-python/ – jdi 2012-04-20 18:47:25

+0

我確實看到了ujson的一個小改進,大約3秒從1.23 min刮掉200MB轉換。然而,這僅僅是一個2TB文件的5分鐘節省「是的一些文件是那麼大」 – secumind 2012-04-20 19:18:36

+0

好吧,那麼我會同意@poke,這裏的瓶頸可能是磁盤IO,你不會看到一個重要的無論有多少處理器或更好的算法,您都可以改善問題。在這裏提高速度的唯一方法是獲得具有更快讀取速度的硬盤驅動器,例如SSD或RAID配置。 – 2012-04-20 19:23:44