我的机器学习脚本生成大量数据(包含在一个根BTree中的数百万个BTree),并将其存储在ZODB的FileStorage中,主要原因是所有这些数据都不适合内存。脚本还经常修改以前添加的数据。
当我增加了问题的复杂性,因此需要存储更多的数据时,我注意到了性能问题--脚本现在平均计算数据的速度从原来的2倍提高到了10倍(唯一改变的是要存储的数据量,以及后来要更改的数据量)。
我尝试将cache_size设置为1000到50000之间的各种值。老实说,速度的差别是可以忽略不计的。
我想切换到RelStorage,但不幸的是,在医生们中,他们只提到了如何配置框架,比如Zope或Plone。我只使用ZODB。
我不知道RelStorage在我的情况下会不会更快。
下面是我当前设置ZODB连接的方式:
import ZODB
connection = ZODB.connection('zodb.fs', ...)
dbroot = connection.root()显然,ZODB目前是我的脚本的瓶颈。我正在寻求关于如何解决这个问题的建议。
我选择了ZODB,因为我认为NoSQL数据库更适合我的情况,我喜欢类似于Python的dict的接口的想法。
代码和数据结构:
actions_values从概念上构建如下:
actions_values ={# BTree str(state):{# BTree # contiains操作(确切地说,我正在处理玩Connect 4的代理程序)#以及它们的值(这里只存在“愤怒者”以前采取的行动),例如: 1: 0.4356 5: 0.3456 },#其他状态}
state是一个简单的二维数组,表示游戏板。它的字段可能有1、2或None:
板= 在xrange(行)中packing也需要很长时间,但这不是主要问题,我可以在程序完成后打包数据库)dbroot上操作的代码(在ReinforcementPlayer中):
get_actions_with_values(self,player_id,如果player_id == 1: lookup_state = state lookup_state :lookup_state= state.switch_players() lookup_state_str = str(lookup_state)如果self.actions_values中的lookup_state_str :返回self.actions_valueslookup_state_str mirror_lookup_state_str =str(lookup_state.mirror() if mirror_lookup_state_str in self.actions_values:返回self.mirror_actions(self.actions_valuesmirror_lookup_state_str)返回None def get_value_of_action(self,player_id,state,action,default=0):actions = self.get_actions_with_values(player_id,state)如果操作为None:返回默认返回actions.get(动作,默认),def set_value_of_action(self,player_id,state,action,值):如果player_id == 1: lookup_state = state lookup_state :lookup_state= state.switch_players() lookup_state_str = str(lookup_state)如果lookup_state_str in self.actions_values: self.actions_valueslookup_state_str = value返回mirror_lookup_state_str = str(lookup_state.mirror())self.actions_values: self.actions_valuesmirror_lookup_state_str = value返回self.actions_valueslookup_state_str = BTree() self.actions_valueslookup_state_str = value
(名称为镜像的函数只需反转列(操作)。因为连接4块板的垂直反射是等价的。)经过550000场比赛,len(dbroot.actions_values)是6018450。
根据iotop,IO操作占90%的时间。
发布于 2016-01-04 19:15:38
使用任何(其他)数据库可能没有帮助,因为它们与ZODB一样受到磁盘IO和内存限制。如果您设法将计算卸载到数据库引擎本身(PostgreSQL +使用SQL脚本),这可能会有所帮助,因为数据库引擎将有更多的信息来做出如何执行代码的智能选择,但是这里没有什么神奇的东西,同样的事情也很可能很容易地用ZODB完成。
一些可以做的事情:
__slots__技巧)拥有一些脚本的代码示例、实际内存和Data.fs大小等,将有助于提供更多的想法。
发布于 2016-01-06 22:15:17
为了澄清这一点,您实际使用的是哪个BTree类?OOBTree?
关于这些树状树的两个方面:
1)每个BTree由多个桶组成。每个桶将持有一定数量的项目,然后被分割。我不记得他们目前持有多少项,但我曾经尝试为它们调整C代码,并重新编译以保存更大的数量,因为所选择的值是在近20年前选择的。
2)有时可以构造非常不平衡的树状树。例如,如果您按排序顺序添加值(例如,只会增加时间戳),那么最终将有一棵树作为O(n)进行搜索。几年前,Jarn的人们编写了一个脚本,它可以在Zope的目录中重新平衡BTrees,这可能适合您。
3)与其使用OOBTree,不如使用OOBucket。这最终只是ZODB中的一个泡菜,所以在您的用例中可能会变得太大,但是如果您在一个事务中完成所有的写操作,速度可能会更快(代价是必须在更新时重写整个Bucket )。
-Matt
https://stackoverflow.com/questions/34597386
复制相似问题