如何在python中有效地更新Gtk.ListStore数据

问题描述

我正处于完成我的程序从 Tkinter 到 Gtk 过渡的最后阶段。最后一步是以有效的方式更新 ListStore。到目前为止,我正在尝试的是工作......但只有大约 15-120 秒才会崩溃(错误代码是 139;有时是没有其他消息的核心转储,有时是“警告:检测到损坏的双链表” )。在运行时,top 报告使用的 RAM 少于 100 MB。

ListStore 包含 51 行和 25 列,创建如下:

def init_ListStore():
    # initialize the main ListStore database
    for symbol in cbp_symbols.keys():
        name = cbp_symbols[symbol]['name']
        row = [symbol,name,0]
        liststore1.append(row)
    treeview1.set_model(liststore1)

    cell = Gtk.CellRendererText()
    columns = list(my_vars['liststore_main']['column_data'].keys())
    for i in range(liststore1.get_n_columns()):
        treeviewcolumn = Gtk.TreeViewColumn(columns[i])
        treeview1.append_column(treeviewcolumn)
        treeviewcolumn.pack_start(cell,True)
        treeviewcolumn.add_attribute(cell,"text",i)

完成后,我执行以下 (3) 个步骤:

更新我的帐户信息(代币余额),从 websocket 获取一条新消息(存储为字典),更新新信息,在单元到单元的基础上,例如:

liststore1[row][col.index('Open')] = float(ticker_data["open_24h"])
liststore1[row][col.index('Last')] = float(ticker_data["price"])
liststore1[row][col.index('Low')] = float(ticker_data["low_24h"])
liststore1[row][col.index('High')] = float(ticker_data["high_24h"])
liststore1[row][col.index('Volume')] = float(ticker_data["volume_24h"])

我希望能够一次性编辑/替换整行;以上似乎缓慢而繁重。初始创建/更新完成后,所有内容都将使用相同的函数完成(每条消息总共要进行大约 20 次更新)。

更新 #1:这次我得到了一个更明确的错误。问题出在 lib/python3.8/site-packages/gI/Overrides/Gtk.py 模块中,第 1680 行:

if GTK2 or GTK3:
    _Gtk_main_quit = Gtk.main_quit

    @override(Gtk.main_quit)
    def main_quit(*args):
        _Gtk_main_quit()

    _Gtk_main = Gtk.main

    @override(Gtk.main)
    def main(*args,**kwargs):
        with register_sigint_fallback(Gtk.main_quit):
            with wakeup_on_signal():
                return _Gtk_main(*args,**kwargs)   << this line

更新 #2:我认为这与多线程锁定有关,但我不知道它是如何工作的(模块由 websocket 客户端导入,而不是由我导入)。我确实尝试对解析传入套接字消息的主函数应用锁定,但没有帮助。我确实知道如果我在没有激活 Gtk 窗口的情况下运行程序,它永远不会崩溃。

解决方法

终于搞定了。诀窍是使用 Gtk.TreeIter 来引用当前行,然后一次性更新整行:

titer = liststore1.get_iter(row)
my_columns = [
    df.columns.get_loc('Last') + 1,df.columns.get_loc('Open') + 1,df.columns.get_loc('Change') + 1,df.columns.get_loc('Change %') + 1,df.columns.get_loc('Low') + 1,df.columns.get_loc('High') + 1,df.columns.get_loc('Value') + 1,df.columns.get_loc('Val Open') + 1,df.columns.get_loc('Port %') + 1,df.columns.get_loc('Cost Basis') + 1,df.columns.get_loc('CB Change') + 1,df.columns.get_loc('Profit') + 1,df.columns.get_loc('Volume') + 1,df.columns.get_loc('30d Avg') + 1,df.columns.get_loc('Vol Act %') + 1,df.columns.get_loc('Trade Val') + 1
]
my_data = [
    df.at[row,'Last'],df.at[row,'Open'],'Change'],'Change %'],'Low'],'High'],'Value'],'Val Open'],'Port %'],'Cost Basis'],'CB Change'],'Profit'],'Volume'],'30d Avg'],'Vol Act %'],'Trade Val']
]
liststore1.set(titer,my_columns,my_data)

我知道这段代码需要精简,但我倾向于先让一些东西工作,然后再简化/精简。