2014-06-16 122 views
4

我想知道json.dump()json.dumps()哪一個在將大數組編碼爲json格式時效率最高。MemoryError using json.dumps()

你能告訴我一個使用json.dump()的例子嗎?

其實我正在製作一個Python CGI,它使用ORM SQlAlchemy從MySQL數據庫獲取大量數據,並且在一些用戶觸發處理之後,我將最終輸出存儲在最終轉換爲Json的數組中。

但轉換成JSON用時:

print json.dumps({'success': True, 'data': data}) #data is my array 

我得到以下錯誤:

Traceback (most recent call last): 
    File "C:/script/cgi/translate_parameters.py", line 617, in  <module> 
f.write(json.dumps(mytab,default=dthandler,indent=4)) 
    File "C:\Python27\lib\json\__init__.py", line 250, in dumps 
    sort_keys=sort_keys, **kw).encode(obj) 
    File "C:\Python27\lib\json\encoder.py", line 209, in encode 
    chunks = list(chunks) 
MemoryError 

所以,我的猜測是使用json.dump()由塊到數據轉換。任何想法如何做到這一點?

或者使用其他想法json.dump()

+0

我不知道實現的細節,但'轉​​儲'輸出到一個字符串,它必須建立並保存在內存中。 'dump'寫出一個文件,我認爲這個文件將會流式傳輸,並且不會將結果保存在內存中。 – Joe

+0

'chunk's由'JSON.Encoder()。iterencode()'生成器生成。看到我的答案。 –

回答

6

只需通過

json.dump(mytab, f, default=dthandler, indent=4) 

更換

f.write(json.dumps(mytab,default=dthandler,indent=4)) 

這應該 「流」 的數據到文件中。

+0

這不起作用,即使假設您的示例中的'mytab'是JSON可串行化的對象'json。dump()'不知道你正在傾倒哪個對象。另外,即使試圖爲大對象仍然產生'MemoryError'。 –

+0

對..忘了mytab作爲參數。固定。關於內存,可能值得嘗試其他的json庫,希望更高效地執行內存...... – sebastian

+0

最終找到了解決方法,發佈我的答案':]' –

3

JSON模塊將在寫入之前分配內存中的整個JSON字符串,這就是爲什麼MemoryError發生。

要解決此問題,使用JSON.Encoder().iterencode()

with open(filepath, 'w') as f: 
    for chunk in json.JSONEncoder().iterencode(object_to_encode): 
     f.write(chunk) 

但是請注意,這通常需要相當一段時間,因爲它在許多小塊一次寫,不是萬能的。


特殊情況:

我有一個Python對象,它是類型的字典列表。像這樣的:

[ 
    { "prop": 1, "attr": 2 }, 
    { "prop": 3, "attr": 4 } 
    # ... 
] 

我可以JSON.dumps()單個對象,但傾倒整個列表生成MemoryError要加快寫作,我打開該文件,並寫了手動的JSON分隔符:

with open(filepath, 'w') as f: 
    f.write('[') 

    for obj in list_of_dicts[:-1]: 
     json.dump(obj, f) 
     f.write(',') 

    json.dump(list_of_dicts[-1], f) 
    f.write(']') 

你可能如果你事先知道你的JSON對象結構,就可以逃避這樣的事情。對於一般用途,請使用JSON.Encoder().iterencode()

+0

這就是'json.dump'的作用:https:// hg .python.org/cpython/file/v2.7.10/Lib/json/__ init __。py#l183 – sebastian

+0

是的,但是如果您嘗試使用大對象,則iterencode()速度太慢 - 最好將塊分割爲內存所在的位置處理,然後將其全部傳遞給encode()。 –