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

2013-10-18 11:23:37 +08:00
 sunhk25
想用Python做个用于转换的应用程序,需要用到几个大的对应表文本文件,
如何将这几个文件转换后用户无法识别,而程序可以?

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

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

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

其中的对应表就是每一行一个中文对应一个译文,如果同一中文对应多个的话就是多行。
对应表文件有三个,中日,中英,英日,每个文件都有上百万条。
如果中日找不到的话,就利用'中英'和'英日'来间接找日文。
------
每次执行时也都要载入大量数据,花时间啊。用pickle能稍微快点,但是还是要一分钟左右。
8146 次点击
所在节点    Python
20 条回复
likuku
2013-10-18 11:27:13 +08:00
mongodb 吧
Golevka
2013-10-18 12:03:49 +08:00
你可以想办法一次读取dict然后常驻内存, 之后再次运行就不用每次从磁盘重新读文件了.
yelite
2013-10-18 12:09:54 +08:00
sqlite,建好索引速度应该还是很快的
daiv
2013-10-18 12:59:18 +08:00
@yelite SQLite 算是文件吧,每次要读取一次呀,
sunhk25
2013-10-18 13:23:05 +08:00
@Golevka 这个不是要总运行的,所以常驻内存没有太大必要。即使是的话,每次初始化后要花大量时间的。
yelite
2013-10-18 13:23:55 +08:00
@daiv 数据库其实我也不是很清楚,有了索引以后好像可以在查询时只读取一小部分的内容。
sunhk25
2013-10-18 13:37:40 +08:00
@likuku 你的意思是说把这三个大文件做成数据库文件,然后通过SQL来操作。
有什么框架可以简单的来处理吗
clino
2013-10-18 13:42:46 +08:00
看起来用数据库比较合适,可以用sqlite试试看,用python的话可以用sqlchemy操作.
clino
2013-10-18 13:52:33 +08:00
上面写错了,是 sqlalchemy
shadowind
2013-10-18 14:37:27 +08:00
好像cpickle会快点~
likuku
2013-10-18 15:20:06 +08:00
@sunhk25 mongodb 很快,基本是拿来作 k-v 存储,就当个比 文本搜索 更快的 hash 表来用就是了。
sunhk25
2013-10-18 16:14:16 +08:00
@likuku 那如果给客户使用时,客户环境是不也得有同样的mongodb环境啊,这样做可能有点困难啊.
czheo
2013-10-18 20:47:03 +08:00
lz可以看看gdbm,local key value storage
likuku
2013-10-18 20:47:57 +08:00
@sunhk25 原来你是要作单机软件啊...抱歉,请忽略。
monkeylyf
2013-10-18 23:59:07 +08:00
pickle
11
2013-10-19 00:10:48 +08:00
pickle 的话,你用的是 pickle 还是 cPickle? cPickle 应该会快一些。
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
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
2013-10-20 22:40:43 +08:00
@czheo useful!many thanks!
v88ex
2013-10-21 13:09:43 +08:00
用radis然后Python连接,算吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/85981

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX