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
sunhk25
V2EX  ›  Python

Python如何保存大容量的对象?

  •  
  •   sunhk25 · 2013-10-18 11:23:37 +08:00 · 8135 次点击
    这是一个创建于 4072 天前的主题,其中的信息可能已经有所发展或是发生改变。
    想用Python做个用于转换的应用程序,需要用到几个大的对应表文本文件,
    如何将这几个文件转换后用户无法识别,而程序可以?

    主要流程就是把输入的文件与对应表文本文件进行匹配,之后转换生成新的文件。

    以前没有做过类似的程序,因为文件的行数总共有四百万左右,如何才能做到输入文件后迅速生成结果文件?

    ------
    我要做的是中日专业术语的翻译,比如一个专利文件用来输入,然后分割成对应表中存在的单词,再利用对应表中对应的译文,做成翻译用的候补选项文件后输出,翻译者利用此文件选择最合适的专业术语译文。

    其中的对应表就是每一行一个中文对应一个译文,如果同一中文对应多个的话就是多行。
    对应表文件有三个,中日,中英,英日,每个文件都有上百万条。
    如果中日找不到的话,就利用'中英'和'英日'来间接找日文。
    ------
    每次执行时也都要载入大量数据,花时间啊。用pickle能稍微快点,但是还是要一分钟左右。
    20 条回复    1970-01-01 08:00:00 +08:00
    likuku
        1
    likuku  
       2013-10-18 11:27:13 +08:00
    mongodb 吧
    Golevka
        2
    Golevka  
       2013-10-18 12:03:49 +08:00   ❤️ 1
    你可以想办法一次读取dict然后常驻内存, 之后再次运行就不用每次从磁盘重新读文件了.
    yelite
        3
    yelite  
       2013-10-18 12:09:54 +08:00
    sqlite,建好索引速度应该还是很快的
    daiv
        4
    daiv  
       2013-10-18 12:59:18 +08:00 via iPhone
    @yelite SQLite 算是文件吧,每次要读取一次呀,
    sunhk25
        5
    sunhk25  
    OP
       2013-10-18 13:23:05 +08:00
    @Golevka 这个不是要总运行的,所以常驻内存没有太大必要。即使是的话,每次初始化后要花大量时间的。
    yelite
        6
    yelite  
       2013-10-18 13:23:55 +08:00
    @daiv 数据库其实我也不是很清楚,有了索引以后好像可以在查询时只读取一小部分的内容。
    sunhk25
        7
    sunhk25  
    OP
       2013-10-18 13:37:40 +08:00
    @likuku 你的意思是说把这三个大文件做成数据库文件,然后通过SQL来操作。
    有什么框架可以简单的来处理吗
    clino
        8
    clino  
       2013-10-18 13:42:46 +08:00
    看起来用数据库比较合适,可以用sqlite试试看,用python的话可以用sqlchemy操作.
    clino
        9
    clino  
       2013-10-18 13:52:33 +08:00
    上面写错了,是 sqlalchemy
    shadowind
        10
    shadowind  
       2013-10-18 14:37:27 +08:00
    好像cpickle会快点~
    likuku
        11
    likuku  
       2013-10-18 15:20:06 +08:00
    @sunhk25 mongodb 很快,基本是拿来作 k-v 存储,就当个比 文本搜索 更快的 hash 表来用就是了。
    sunhk25
        12
    sunhk25  
    OP
       2013-10-18 16:14:16 +08:00
    @likuku 那如果给客户使用时,客户环境是不也得有同样的mongodb环境啊,这样做可能有点困难啊.
    czheo
        13
    czheo  
       2013-10-18 20:47:03 +08:00
    lz可以看看gdbm,local key value storage
    likuku
        14
    likuku  
       2013-10-18 20:47:57 +08:00
    @sunhk25 原来你是要作单机软件啊...抱歉,请忽略。
    monkeylyf
        15
    monkeylyf  
       2013-10-18 23:59:07 +08:00
    pickle
    11
        16
    11  
       2013-10-19 00:10:48 +08:00
    pickle 的话,你用的是 pickle 还是 cPickle? cPickle 应该会快一些。
    czheo
        17
    czheo  
       2013-10-19 19:16:51 +08:00
    我对pickle, cpickle和gdbm做了下简单测试,读写400万条数据,分别都做3次测试,结果如下:
    ##############################
    先让我们看下,cpickle
    1st round:
    write: 16.770192 s
    read: 12.779067 s
    2nd round:
    write: 16.756108 s
    read: 12.965158 s
    3rd round:
    write: 16.915888 s
    read: 13.199477 s
    ##############################
    然后是,pickle
    1st round:
    write: 56.681483 s
    read: 60.116578 s
    2nd round:
    write: 55.843203 s
    read: 57.877304 s
    3rd round:
    write: 56.738194 s
    read: 59.350219 s
    ##############################
    最后是,gdbm
    1st round:
    write: 45.324347 s
    read: 5.723811 s
    2nd round:
    write: 10.359093 s
    read: 5.929302 s
    3rd round:
    write: 10.596857 s
    read: 6.014081 s
    ##############################
    生成的文件大小如下:
    330M Oct 19 19:57 gdbm.db
    153M Oct 19 19:46 cpickle.db
    153M Oct 19 19:53 pickle.db

    可以看出,除去gdbm第一次建立数据库需要花费更多时间外,读写都比cpickle快很多。

    最重要的一点是:
    虽然没有具体做内存方面的测试,
    但cpickle每次都要读取整个文件载入内存,效率显然不行。
    gdbm属于kvs,对这方面做了大量优化,内存使用方面应该可以完胜。
    实际跑测试程序的时候,用top看了一眼内存使用,肉眼观测,pickle/cpickle都要用掉1G左右的,而gdbm内存使用几乎没有什么变化。

    如果需要以后添加修改数据,cpickle需要重写整个文件,而gdbm可以动态添加修改某条纪录,使用起来显然更方便。

    最后,如果多个process去写同一个文件,cpickle无法保证安全性可能会导致文件损坏。而gdbm有自动lock机制,安全方面要好很多。

    另外,个人觉得sqlite其实也是一个不错的选择,性能上可能不及gdbm,但更flexible。

    结论:
    推荐gdbm
    czheo
        18
    czheo  
       2013-10-19 19:20:49 +08:00
    附上测试代码 供lz参考
    ############## cpickle.py #################
    import cPickle as pickle
    import time
    start = time.clock()

    db = {};
    for i in range(4000000):
    db[str(i)] = str(i)
    f = open("cpickle.db", "wb")
    pickle.dump(db, f)
    f.close()

    end = time.clock()
    print "write: %f s" % (end - start)

    start = time.clock()
    f=open("cpickle.db", "rb")
    db = pickle.load(f)
    for i in db:
    if int(i) % 1000000 == 0:
    print i, db[i]
    f.close()

    end = time.clock()
    print "read: %f s" % (end - start)

    ############## gdbm.py #################

    import gdbm
    import time

    start = time.clock()

    db = gdbm.open("gdbm.db", "c")
    for i in range(4000000):
    db[str(i)] = str(i)
    db.close()

    end = time.clock()
    print "write: %f s" % (end - start)

    start = time.clock()

    db = gdbm.open("gdbm.db", "r")
    for i in db.keys():
    if int(i) % 1000000 == 0:
    print i, db[i]
    db.close()

    end = time.clock()

    print "read: %f s" % (end - start)

    ############## pickle.py #################

    import pickle
    import time
    # timmer code
    start = time.clock()

    # real code
    db = {};
    for i in range(4000000):
    db[str(i)] = str(i)
    f = open("pickle.db", "wb");
    pickle.dump(db, f)
    f.close()

    #timmer code
    end = time.clock()
    print "write: %f s" % (end - start)

    start = time.clock()
    f=open("pickle.db", "rb")
    db = pickle.load(f)
    for i in db:
    if int(i) % 1000000 == 0:
    print i, db[i]
    f.close()

    end = time.clock()
    print "read: %f s" % (end - start)
    stefwoo
        19
    stefwoo  
       2013-10-20 22:40:43 +08:00
    @czheo useful!many thanks!
    v88ex
        20
    v88ex  
       2013-10-21 13:09:43 +08:00
    用radis然后Python连接,算吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1747 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:19 · PVG 00:19 · LAX 08:19 · JFK 11:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.