【问题标题】:Performance issues formatting using .json()使用 .json() 格式化的性能问题
【发布时间】:2015-08-14 18:06:58
【问题描述】:

我正在尝试从位于某个 URL 的文件中加载数据。我使用请求来获取它(这发生得很快)。但是,使用 r.json() 格式化部分字典大约需要 10 分钟。如何加快速度?

match_list = []
for i in range(1, 11):
    r = requests.get('https://s3-us-west-1.amazonaws.com/riot-api/seed_data/matches%d.json' % i)
    print('matches %d of 10 loaded' % i)
    match_list.append(r.json()['matches'])
    print('list %d of 10 created' % i)
match_histories = {}
match_histories['matches'] = match_list

我知道这里有一个相关问题:Performance problem transforming JSON data,但我不知道如何将其应用于我的案例。谢谢! (我使用的是 Python 3)。

编辑:

我收到了很多看起来很有希望的建议,但每一个我都遇到了障碍。

  • 我想尝试 cjson,但我无法安装它(pip 找不到 MS Visual C++ 10.0,尝试使用 Lua 进行一些安装,但我的路径中需要 cl 才能开始;)。

  • json.loads(r.content) 在 Python 3 中导致 TypeError。

  • 我不确定如何让 ijson 工作。

  • ujson 似乎需要和 json 一样长的时间

  • json.loads(r.text.encode('utf-8').decode('utf-8')) 也同样耗时

【问题讨论】:

  • 你确定是json转换特别需要时间吗?当我尝试这个时,我发现即使r.content 也需要很长时间。从我看到的响应内容大约是 19MB。创建一个 19MB 的字符串将需要很长时间,即使您不尝试将其解析为 json。
  • 呃,19MB 太小了。但我确实看到json.load 不认为它是有效的JSON,所以json.loads(r.content) 引发UnicodeDecodeError: 'utf8' codec can't decode byte 0xc3 in position 0: invalid continuation byte。我敢打赌r.json() 在异常处理上花费了大量时间。
  • 我必须将数据解码为 un​​icode 才能使用它:data = json.loads(r.text.encode('utf-8').decode('utf-8'))
  • 我没有收到您遇到的 UnicodeDecode 错误。您是否做了一些特别的事情来查看该错误消息?知道如何减少异常处理所花费的时间吗?
  • 他可能正在使用 Python 2。您必须特别注意 Python 2 中的 Unicode。

标签: python json python-3.x


【解决方案1】:

内置的 JSON 解析器并不是特别快。我尝试了另一个解析器,python-cjson,如下所示:

import requests
import cjson

r = requests.get('https://s3-us-west-1.amazonaws.com/riot-api/seed_data/matches1.json')
print cjson.decode(r.content)

整个程序在我的笔记本电脑上耗时 3.7 秒,包括获取数据和格式化输出以供显示。

编辑:哇,我们都走错了路。 json 不慢; Requests 的字符集检测非常缓慢。试试这个:

import requests
import json

r = requests.get('https://s3-us-west-1.amazonaws.com/riot-api/seed_data/matches1.json')
r.encoding = 'UTF-8'
print json.loads(r.text)

json.loads 部分在我的同一台笔记本电脑上需要 1.5 秒。这仍然比 cjson.decode 慢(仅 0.62 秒),但可能足够快,以至于您不会在意这是否不是您经常运行的东西。警告:我只在 Python2 上对此进行了基准测试,在 Python3 上可能会有所不同。

编辑 2: 似乎 cjson 没有安装在 Python3 中。没关系:json.loads 在这个版本中只需要 0.54 秒。但是,字符集检测仍然很缓慢,评论r.encoding = 'UTF-8' 仍然会使测试脚本在 O(eternal) 时间内运行。如果您可以指望这些文件始终是 UTF-8 编码的,我认为性能秘诀是将这些信息放入您的脚本中,这样它就不必在运行时解决这个问题。有了这种提升,您无需费心提供自己的 JSON 解析器。运行:

import requests

r = requests.get('https://s3-us-west-1.amazonaws.com/riot-api/seed_data/matches1.json')
r.encoding = 'UTF-8'
print r.json()

【讨论】:

  • 我被撕裂了!我想为您向我展示 cjson 库的答案投票 +1,但我不想为您的答案投票,因为您没有向他展示如何将数据编码为 un​​icode。
  • 这个答案非常彻底,谢谢。我在安装 cjson 时遇到问题。我只是使用 pip 安装 ijson ......但是它找不到 cjson (对不起,我对编程有点陌生,不熟悉进行此类安装的最佳方法)。
  • @nivixzixer 啊!多么尴尬;你是对的。顺便说一句,r.textr.content 的 unicode 版本。 @Mark(你到底是怎么得到 that 用户名的?!?)包名是整个字符串:python-cjson。像“pip install python-cjson”一样安装它。
  • requests 模块在调用r.json() 时默认使用simplejson,这里是a link to benchmarking of ujson, simplejson and jsonujson 实际上在 Python 3.5.2 中最适合我。
【解决方案2】:

我建议使用流式 JSON 解析器(查看 ijson)。流式处理方法将提高解析步骤的内存效率,但您的程序可能仍然缓慢,因为您在内存中存储了相当大的数据集。

【讨论】:

    【解决方案3】:

    嗯,这是一个非常大的文件,而且纯 python 代码(我怀疑请求库不使用 C 绑定进行 JSON 解析)通常相当慢。你真的需要所有的数据吗?如果您只需要它的某些部分,也许您可​​以找到一种更快的方法来找到它,或者在可用的情况下使用不同的 API。

    您也可以尝试使用更快的 JSON 库,例如使用 ujson 之类的库:https://pypi.python.org/pypi/ujson

    我自己没有尝试过这个,但它声称速度很快。然后,您只需拨打ujson.loads(r.text) 即可获取您的数据。

    【讨论】:

      【解决方案4】:

      看起来requests 使用simplejson 来解码JSON。如果您只是使用r.content 获取数据,然后使用Python 内置的json 库,json.loads(r.content) 的工作速度非常快。它通过引发无效 JSON 的错误来工作,但这比长时间挂起要好。

      【讨论】:

      • json.loads(r.content) 在设置 r=requests.get(BLA....) 后立即导致 TypeError:JSON 对象必须是 str,而不是 'bytes'。
      • @Mark:大概您正在运行 Python 3。Python 2 上不会出现该错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 2017-08-25
      • 1970-01-01
      • 2012-06-03
      相关资源
      最近更新 更多