V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
RicardoScofileld
V2EX  ›  Python

有一个很大的 json 文件,要如何才能将它读到内存中呢, 4 个多 G

  •  1
     
  •   RicardoScofileld · 2018-06-05 11:40:12 +08:00 · 15353 次点击
    这是一个创建于 2397 天前的主题,其中的信息可能已经有所发展或是发生改变。

    尝试用 pickle.loads 读到内存,直接内存溢出了,试着用 pandas.read_json()读取,但是报错,Excepted object or value 黔驴技穷,不知道该咋弄了

    第 1 条附言  ·  2018-06-05 15:42:51 +08:00
    可能我的描述出了点问题,该对象是用 pickle.dump 出去的,然后再 load 进来的时候,会内存溢出。。。。。
    60 条回复    2018-06-14 17:14:36 +08:00
    opengps
        1
    opengps  
       2018-06-05 11:45:46 +08:00
    要不你试试用工具把内存映射成硬盘,然后当作硬盘读写?
    不过貌似没有长期免费的内存映射硬盘工具
    purebluesong
        2
    purebluesong  
       2018-06-05 12:17:48 +08:00
    怎么写的怎么读吧,python 的 loads 会在内存中占用成 10 倍磁盘空间的大小。
    不过如果 Expected object or value 的话应该这个文件本身就有问题了,说不定因为文件大小限制而被截断了
    Luckyray
        3
    Luckyray  
       2018-06-05 12:18:41 +08:00 via iPhone
    这么大还用 json 不太合适吧……
    likuku
        4
    likuku  
       2018-06-05 12:20:27 +08:00
    某些数据库已经支持 Json 数据类型了,先塞进去,Py 再去读 DB 呢?
    zynlp
        5
    zynlp  
       2018-06-05 12:20:48 +08:00 via iPhone   ❤️ 1
    加内存,就是这么直接
    janxin
        6
    janxin  
       2018-06-05 12:21:33 +08:00
    才 4 个 G 不会爆内存的吧...你内存不够了?
    ho121
        7
    ho121  
       2018-06-05 12:25:21 +08:00 via Android   ❤️ 1
    自己写个 json 解释器,支持流式读取
    twor2
        8
    twor2  
       2018-06-05 12:25:23 +08:00 via iPhone
    开一个临时的大内存云服务器
    lesteryu
        9
    lesteryu  
       2018-06-05 12:31:19 +08:00   ❤️ 1
    pip install ijson
    Bramblex2
        10
    Bramblex2  
       2018-06-05 12:38:59 +08:00 via iPhone
    你这 json 什么结构啊…如果层数深还是长度长?
    maxco292
        11
    maxco292  
       2018-06-05 13:11:53 +08:00
    iwtbauh
        12
    iwtbauh  
       2018-06-05 13:36:02 +08:00 via Android   ❤️ 1
    @opengps Linux 自带 mount -t tmpfs 了解一下,内存文件系统,比内存盘还要高效
    shilyx
        13
    shilyx  
       2018-06-05 13:36:52 +08:00
    将你的需求映射为数据接口由 c++来处理,C++用 rapidjson 来读取

    rapidjson 如果还是不行,就用 c++写一个针对文件的、有限功能的 json 库

    如果自己搞不定,就外包
    iwtbauh
        14
    iwtbauh  
       2018-06-05 13:37:34 +08:00 via Android
    使用 64 位处理器,64 位操作系统和 64 位 Python 尝试

    从理论上讲,64 位进程的虚拟内存可以高达 EB 级别( 32 位进程的虚拟内存通常只有 2GB 或 3GB,不可能超过 4GB )
    scriptB0y
        15
    scriptB0y  
       2018-06-05 13:41:56 +08:00
    建议使用 less 这种文本阅读工具看一下内容,然后根据内容用代码一部分一部分的读然后切成小文件,应该是比较快的方法。
    lihongjie0209
        16
    lihongjie0209  
       2018-06-05 13:57:00 +08:00
    为什么不先导入到数据库
    graysheeep
        17
    graysheeep  
       2018-06-05 14:05:39 +08:00
    搞策略交易么
    est
        18
    est  
       2018-06-05 14:07:16 +08:00
    #9 楼 @lesteryu 回复正解。迭代式解析 json 即可。内存绝对不会爆炸。
    RicardoScofileld
        19
    RicardoScofileld  
    OP
       2018-06-05 14:23:07 +08:00
    @opengps 没接触过这种工具,推荐一个谢谢啦
    RicardoScofileld
        20
    RicardoScofileld  
    OP
       2018-06-05 14:24:38 +08:00
    @purebluesong 你说为啥 load 的时候,会达到文件本身 10 倍的内存占用呢,是因为 Python 的数据类型导致的吗
    RicardoScofileld
        21
    RicardoScofileld  
    OP
       2018-06-05 14:25:39 +08:00
    @Luckyray 哎,我老大写的代码,要我优化,他服务器 32 个 G 的内存,给我开了一个 8G 的,我跑代码特么的动不动就内存溢出。真的头大
    RicardoScofileld
        22
    RicardoScofileld  
    OP
       2018-06-05 14:26:17 +08:00
    @zynlp 真粗暴,有没有什么免费的骚操作
    RicardoScofileld
        23
    RicardoScofileld  
    OP
       2018-06-05 14:27:01 +08:00
    @janxin 文件大小虽然是 4 个 G,但是 load 的时候会造成很多倍的内存占用,也不知道为什么
    RicardoScofileld
        24
    RicardoScofileld  
    OP
       2018-06-05 14:27:44 +08:00
    @ho121 大佬,可以来个示范代码或者链接吗,万分感激
    RicardoScofileld
        25
    RicardoScofileld  
    OP
       2018-06-05 14:28:48 +08:00
    @twor2 公司 32G 的服务器,也会跑崩
    RicardoScofileld
        26
    RicardoScofileld  
    OP
       2018-06-05 14:29:18 +08:00
    @lesteryu 查阅相关资料的时候看到这个库,我去了解一下
    RicardoScofileld
        27
    RicardoScofileld  
    OP
       2018-06-05 14:29:34 +08:00
    @Bramblex2 字典,嵌套字典
    RicardoScofileld
        28
    RicardoScofileld  
    OP
       2018-06-05 14:31:32 +08:00
    @lihongjie0209 这算一个临时的中间文件,所以没有保存数据库
    RicardoScofileld
        29
    RicardoScofileld  
    OP
       2018-06-05 14:36:18 +08:00
    @iwtbauh Python 版本倒是 64 位的其他就不知道了
    RicardoScofileld
        30
    RicardoScofileld  
    OP
       2018-06-05 14:38:53 +08:00
    @shilyx 小弟的水平看来只能 GG 了
    linuxchild
        31
    linuxchild  
       2018-06-05 14:54:26 +08:00
    单机 spark 试试?
    USNaWen
        32
    USNaWen  
       2018-06-05 14:59:48 +08:00
    rapidjson,用 SAX+流式。
    https://github.com/Tencent/rapidjson
    ipeony
        33
    ipeony  
       2018-06-05 15:13:26 +08:00
    导 mongodb 里
    flyingghost
        34
    flyingghost  
       2018-06-05 15:47:43 +08:00   ❤️ 4
    首先,先搞清楚你把数据加载到内存后打算干吗。
    这坨数据就是比你内存大,和格式无关。哪怕它是再精简不过的 bin 格式,哪怕我用 c,都无法解决 8G 内存读取 800G 数据的矛盾。
    唯一的出路,就是根据数据格式和需求确定解析和计算模式,部分解析,部分计算,分治然后汇总。

    建议的几种读取方式:
    1,SAX 了解一下,事件流驱动的 xml 解析思路,搬到 json 上毫无问题。
    2,切割原 json 文件,给它补上恰当的开始、关闭符来确保结构。
    3,自己实现解析器,最 low 的状态机实现起来很简单的。然后一边解析一边处理一边丢弃。
    4,如果 json 数据有某种特征,预处理一下。(比如结构体其实不复杂元素也不多,但里面有个字段的值超大,那么先文本处理 json,把这个字段抽取出来形成外部文件,json 内只留个文件名索引)其实很多超大数据集要么结构简单只是数据条数多,要么条数不多但单条比较大,很容易做针对性处理。
    yedashuai
        35
    yedashuai  
       2018-06-05 15:49:46 +08:00
    这是使用 generator 的最佳场景呀,流式读取和解析~~~
    RicardoScofileld
        36
    RicardoScofileld  
    OP
       2018-06-05 15:56:51 +08:00
    @flyingghost 这个本来是很多个文件处理后生成的一个字典,然后用 pickle dump 出去,生成一个临时中间文件,避免下次使用的时候还要经过计算生成,但是在 load 的时候,不知道为什么内存占用会成倍的增长。
    RicardoScofileld
        37
    RicardoScofileld  
    OP
       2018-06-05 15:57:26 +08:00
    @yedashuai 用 pickle 生成的文件,要如何流式读取解析呢
    henglinli
        38
    henglinli  
       2018-06-05 16:28:49 +08:00 via iPhone
    这就是典型设计问题啊
    jyf
        39
    jyf  
       2018-06-05 16:39:07 +08:00
    有流式解析的 不过这要看你的数据本身的结构 34 楼已经说得很清楚了
    RedFlag2233
        40
    RedFlag2233  
       2018-06-05 16:48:49 +08:00 via Android
    with as 😯
    crist
        41
    crist  
       2018-06-05 17:00:32 +08:00
    请装 16G 的内存,谢谢。
    focusheart
        42
    focusheart  
       2018-06-05 18:05:51 +08:00
    嗯,看了补充内容,标题有歧义。
    标题的一般理解是有个 4G 多的 xxx.json 的纯文本文件。
    而实际上是一个 pickle dump 出来的对象文件比如 xxx.pkl 。
    显然用 pd.read_json() 是无法读取这个 xxx.pkl 的,也不用考虑流式之类的问题。

    这样几种方法解决:
    1. 如#41 所说,加内存,简单有效省事。
    2. 用 json 的话,重新用 json.dump() 搞一个纯文本的 xxx.json。纯文本怎么都好办。
    3. pickle 并不适合搞大对象的保存。换个库来做对象序列化,marsahl 好一些,但是要注意 python 版本。
    diggerdu
        43
    diggerdu  
       2018-06-05 18:54:34 +08:00
    临时加个 swapfile
    aimiyooo
        44
    aimiyooo  
       2018-06-05 23:28:00 +08:00
    4 个 G 数据,加载到内存可远远不止 4G
    exhades
        45
    exhades  
       2018-06-06 00:03:25 +08:00
    加内存咯....不过全部加载到内存干什么.....
    qwertyegg
        46
    qwertyegg  
       2018-06-06 01:17:41 +08:00
    NoSQL
    feiffy
        47
    feiffy  
       2018-06-06 09:07:45 +08:00
    如果都是条数多,嵌套层数少,相同元素多,可以流式读取文件,generator 处理啊
    RicardoScofileld
        48
    RicardoScofileld  
    OP
       2018-06-06 09:24:16 +08:00
    @jyf 额 是我的描述出了点问题,pickle.dump 是异于 json.dump 的,是一个超大的字典,dump 出去有 4 个多 G,但是 load 的时候内存占用成倍的增长,直接溢出
    RicardoScofileld
        49
    RicardoScofileld  
    OP
       2018-06-06 09:25:14 +08:00
    @crist 文件达到将近 5 个 G 的时候,32G 内存服务器偶尔会崩。。。。
    RicardoScofileld
        50
    RicardoScofileld  
    OP
       2018-06-06 09:26:58 +08:00
    @focusheart 是啊,我原以为这两个库作用是相同的,查阅资料的时候才发现是有区别的,误导了大家了,尴尬
    RicardoScofileld
        51
    RicardoScofileld  
    OP
       2018-06-06 09:27:23 +08:00
    @diggerdu 谢谢,我去了解一下
    RicardoScofileld
        52
    RicardoScofileld  
    OP
       2018-06-06 09:29:17 +08:00
    @aimiyooo 是啊,pickle dump 出去只有 4 个 G,load 进来的时候却成倍的增长,是不是因为数据结构的原因呢
    RicardoScofileld
        53
    RicardoScofileld  
    OP
       2018-06-06 09:31:28 +08:00
    @exhades 是经过处理计算的一个字典,为了减少下次运算时间,所以打算用空间换取时间,dump 出一个中间临时文件,到时候直接 load 进来的
    RicardoScofileld
        54
    RicardoScofileld  
    OP
       2018-06-06 09:34:07 +08:00
    @qwertyegg 如果用 nosql,我想了一下,对于 redis,貌似只能用 hash 类型,但是这个字典里面有嵌套,要保存的话,还是需要序列化
    lfzyx
        55
    lfzyx  
       2018-06-06 10:16:19 +08:00
    大多数应用程序都必须检索整个对象,然后仅过滤出所需数据以进行进一步分析。借助 S3 Select,应用程序可以将过滤和访问对象内部数据的繁重工作卸载到 Amazon S3 服务。

    https://aws.amazon.com/cn/about-aws/whats-new/2018/04/amazon-s3-select-is-now-generally-available/?nc1=f_ls
    ofooo
        56
    ofooo  
       2018-06-06 11:06:13 +08:00
    你老大 32G 内存,你就和你老大说一下不就完了吗。需求不合理就提。
    liangeeks
        57
    liangeeks  
       2018-06-06 11:58:06 +08:00
    这么大,知道数据结构的话慢慢读,不用一次性 load 啊
    RicardoScofileld
        58
    RicardoScofileld  
    OP
       2018-06-06 13:53:34 +08:00
    @liangeeks pickle dump 出去的,怎么慢慢读呢
    cctv1005s927
        59
    cctv1005s927  
       2018-06-06 14:48:33 +08:00
    自己搞一个数据结构存放文件吧,json 的文件是有深度的,有些时候不读取完毕很难读取到一个 object 的内容。
    beforeuwait
        60
    beforeuwait  
       2018-06-14 17:14:36 +08:00
    用 生成器呀
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   993 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:39 · PVG 03:39 · LAX 11:39 · JFK 14:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.