gpt4 book ai didi

python - 如何提高处理大量数据的脚本的性能?

转载 作者:行者123 更新时间:2023-11-30 08:54:56 25 4
gpt4 key购买 nike

我的机器学习脚本生成大量数据(一个根 BTree 中包含数百万个 BTree)并将其存储在 ZODB 的 FileStorage 中,主要是因为所有这些都无法放入 RAM 中。脚本还经常修改先前添加的数据。

当我增加问题的复杂性,因此需要存储更多数据时,我注意到性能问题 - 脚本现在计算数据的速度平均慢两倍甚至十倍(唯一改变的是数据量)进行存储并稍后检索以进行更改)。

我尝试将 cache_size 设置为 1000 到 50000 之间的各种值。说实话,速度差异可以忽略不计。

我想过切换到 RelStorage 但不幸的是在 the docs 中他们只提到了如何配置 Zope 或 Plone 等框架。我只使用 ZODB。

我想知道 RelStorage 在我的情况下是否会更快。

以下是我当前设置 ZODB 连接的方式:

import ZODB
connection = ZODB.connection('zodb.fs', ...)
dbroot = connection.root()

我很清楚 ZODB 目前是我脚本的瓶颈。我正在寻求有关如何解决此问题的建议。

我选择 ZODB 是因为我认为 NoSQL 数据库更适合我的情况,而且我喜欢类似于 Python 的 dict 的界面理念。

<小时/>

代码和数据结构:

  • 根数据结构:

    if not hasattr(dbroot, 'actions_values'):
    dbroot.actions_values = BTree()

    if not hasattr(dbroot, 'games_played'):
    dbroot.games_played = 0

    actions_values 在概念上构建如下:

    actions_values = { # BTree
    str(state): { # BTree
    # contiains actions (coulmn to pick to be exact, as I'm working on agent playing Connect 4)
    # and their values(only actions previously taken by the angent are present here), e.g.:
    1: 0.4356
    5: 0.3456
    },
    # other states
    }

    state 是一个表示游戏板的简单二维数组。其字段的可能值为 12None:

    board = [ [ None ] * cols for _ in xrange(rows) ]

    (在我的例子中,行数 = 6 和列数 = 7)

  • 主循环:

    should_play = 10000000
    transactions_freq = 10000
    packing_freq = 50000

    player = ReinforcementPlayer(dbroot.actions_values, config)

    while dbroot.games_played < should_play:
    # max_epsilon at start and then linearly drops to min_epsilon:
    epsilon = max_epsilon - (max_epsilon - min_epsilon) * dbroot.games_played / (should_play - 1)

    dbroot.games_played += 1
    sys.stdout.write('\rPlaying game %d of %d' % (dbroot.games_played, should_play))
    sys.stdout.flush()

    board_state = player.play_game(epsilon)

    if(dbroot.games_played % transactions_freq == 0):
    print('Commiting...')
    transaction.commit()
    if(dbroot.games_played % packing_freq == 0):
    print('Packing DB...')
    connection.db().pack()

    (打包也需要很多时间,但这不是主要问题;我可以在程序完成后打包数据库)

  • dbroot 上运行的代码(在 ReinforcementPlayer 内):

    def get_actions_with_values(self, player_id, state):
    if player_id == 1:
    lookup_state = state
    else:
    lookup_state = state.switch_players()
    lookup_state_str = str(lookup_state)
    if lookup_state_str in self.actions_values:
    return self.actions_values[lookup_state_str]
    mirror_lookup_state_str = str(lookup_state.mirror())
    if mirror_lookup_state_str in self.actions_values:
    return self.mirror_actions(self.actions_values[mirror_lookup_state_str])
    return None

    def get_value_of_action(self, player_id, state, action, default=0):
    actions = self.get_actions_with_values(player_id, state)
    if actions is None:
    return default
    return actions.get(action, default)

    def set_value_of_action(self, player_id, state, action, value):
    if player_id == 1:
    lookup_state = state
    else:
    lookup_state = state.switch_players()
    lookup_state_str = str(lookup_state)
    if lookup_state_str in self.actions_values:
    self.actions_values[lookup_state_str][action] = value
    return
    mirror_lookup_state_str = str(lookup_state.mirror())
    if mirror_lookup_state_str in self.actions_values:
    self.actions_values[mirror_lookup_state_str][self.mirror_action(action)] = value
    return
    self.actions_values[lookup_state_str] = BTree()
    self.actions_values[lookup_state_str][action] = value

    (名称中带有mirror的函数只是简单地反转列( Action )。这样做是因为连接4 block 彼此垂直反射的板是等效的。)

<小时/>

550000 场比赛后 len(dbroot.actions_values) 为 6018450。

<小时/>

根据 iotop IO 操作占用了 90% 的时间。

最佳答案

使用任何(其他)数据库可能都没有帮助,因为它们与 ZODB 一样受到相同的磁盘 IO 和内存限制。如果您设法将计算卸载到数据库引擎本身(PostgreSQL + 使用 SQL 脚本),它可能会有所帮助,因为数据库引擎将有更多信息来做出如何执行代码的明智选择,但这里没有什么神奇的,同样的事情也可以使用 ZODB 很可能可以轻松完成。

一些可以做什么的想法:

  • 拥有数据索引而不是加载完整对象(相当于SQL“全表扫描”)。保持智能预处理数据副本:索引、总和、部分。

  • 使对象本身更小(Python 类有 __slots__ 技巧)

  • 以智能方式使用交易。不要尝试在一个大块中处理所有数据。

  • 并行处理 - 使用所有 CPU 核心而不是单线程方法

  • 不要使用 BTree - 也许有更适合您的用例的方法

拥有一些脚本代码示例、实际 RAM 和 Data.fs 大小等将有助于提供进一步的想法。

关于python - 如何提高处理大量数据的脚本的性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34597386/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com