由于排序,GtkTreeView插入/更新性能损失 [英] GtkTreeView insert/update performance penalty because of sorting

查看:216
本文介绍了由于排序,GtkTreeView插入/更新性能损失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将多行插入到GTK树视图(使用PyGTK)时 - 或修改多行时,我遇到了性能问题。问题在于,模型似乎在每次更改(插入/修改)后都会采用。这会导致GUI挂起几秒钟。通过注释 model.set_sort_column_id(SOME_ROW_INDEX,gtk.SORT_ASCENDING)留下模型未排序可消除这些问题。

因此,

,我想在插入或修改模型时禁用排序,然后重新启用它。不幸的是,使用 model.set_sort_column_id(-1,gtk.SORT_ASCENDING)不能禁用排序。使用冻结/解冻函数也不起作用:



treeview.freeze_child_notify()

尝试:
用于模型中的行:
#...更改行中的某些内容...
finally:
treeview.thaw_child_notify()

那么,如何禁用排序呢?或者是否有更好的批量插入/修改方法?






解决方案



感谢bobince在他的回答中提供的信息和链接,我检查了一些替代方案:

1 )虚拟排序

tv.freeze_child_notify()
sortSettings = model .get_sort_column_id()
model.set_default_sort_func(lambda * unused:0)#< - 也可以使用None,但速度较慢!
#model.set_default_sort_func(lambda * unused:1)< - slow
#model.set_default_sort_func(lambda * unused:-1)< - crash(gtk_tree_store_move_after ?!中的访问冲突)
model.set_sort_column_id(-1,gtk.SORT_ASCENDING)
#更改行
model.set_sort_column_id(* sortSettings)
tv.thaw_child_notify()

这将时间从大约11秒缩短到2秒。哇!但可能会更好,这是只有1000行。



2)更新时删除模型

tv.set_model(None)
#change rows
tv.set_model(model)

没有明显的区别,11秒。

3)虚拟排序和来自 PyGTK FAQ

def gen():
tv.freeze_child_notify ()
sortSettings = model.get_sort_column_id()
model.set_default_sort_func(lambda * unused:0)
model.set_sort_column_id(-1,gtk.SORT_ASCENDING)

i = 0
行中的行更改:
i + = 1
#更改某事
如果我%200 == 0:
#冻结/解冻并不是真的需要他因为
#默认排序函数
yield True

model.set_sort_column_id(* sortSettings)
tv.thaw_child_notify()
如果g.next():#现在运行一次,空闲时剩余的迭代
gobject.idle_add(g.next)

结果:与解决方案1)中估计的2秒相同,但在此期间GUI会作出反应。我更喜欢这种方法。如果需要的话,可以调整模200以使GUI或多或少具有反应性。

也许甚至可以继承 gtk.TreeStore 获得更好的结果?还没有尝试过,但选项3)现在已经够用了。

解决方案

听起来就像你快到了。有关更多说明,请参见 FAQ 。尤其是,您还应该设置 default_sort_order (您现在可以使用 None 以及虚拟比较lambda例如,为了获得更好的性能),以确保没有排序,并在操作期间从树视图中移除模型。



如果有很多更改,您可以最好创建并设置一个完整的新模型。


I'm having performance problems when inserting many rows into a GTK treeview (using PyGTK) - or when modifying many rows. The problem is that the model seems to get resorted after each change (insert/modification). This causes the GUI to hang for multiple seconds. Leaving the model unsorted by commenting out model.set_sort_column_id(SOME_ROW_INDEX, gtk.SORT_ASCENDING) eliminates these problems.

Therefore, I would like to disable the sorting while I'm inserting or modifying the model, and re-enable it afterwards. Unfortunately, sorting can't be disabled with model.set_sort_column_id(-1, gtk.SORT_ASCENDING). Using the freeze/thaw functions doesn't work either:

treeview.freeze_child_notify()

try:
    for row in model:
        # ... change something in row ...
finally:
    treeview.thaw_child_notify()

So, how can I disable the sorting? Or is there a better method for bulk inserts/modifications?


Solution

Thanks to the information and links bobince provided in his answer, I checked out some of the alternatives:

1) Dummy sorting

 tv.freeze_child_notify()
 sortSettings = model.get_sort_column_id()
 model.set_default_sort_func(lambda *unused: 0) # <-- can also use None but that is slower!
 # model.set_default_sort_func(lambda *unused: 1) <-- slow
 # model.set_default_sort_func(lambda *unused: -1) <-- crash (access violation in gtk_tree_store_move_after?!)
 model.set_sort_column_id(-1, gtk.SORT_ASCENDING)
 # change rows
 model.set_sort_column_id(*sortSettings)
 tv.thaw_child_notify()

This brought the time down from about 11 seconds to 2 seconds. Wow! But could be better, this was only for 1000 rows.

2) Removing model while updating

tv.set_model(None)
# change rows
tv.set_model(model)

No noticable difference, 11 seconds.

3) Dummy sorting and the cool generator trick from the PyGTK FAQ

 def gen():
      tv.freeze_child_notify()
      sortSettings = model.get_sort_column_id()
      model.set_default_sort_func(lambda *unused: 0)
      model.set_sort_column_id(-1, gtk.SORT_ASCENDING)

      i = 0
      for row in rowsToChange:
           i += 1
           # change something
           if i % 200 == 0:
                # freeze/thaw not really  necessary here as sorting is wrong because of the
                # default sort function
                yield True

      model.set_sort_column_id(*sortSettings)
      tv.thaw_child_notify()
      yield False

 g = gen()
 if g.next(): # run once now, remaining iterations when idle
     gobject.idle_add(g.next)

The result: The same estimated 2 seconds as in solution 1), but the GUI reacts during this time. I prefer this method. The modulo 200 can be tweaked to make the GUI more or less reactive if needed.

Maybe it's even possible to subclass gtk.TreeStore to get better results? Haven't tried that yet, but option 3) is good enough for now.

解决方案

Sounds like you're nearly there. See the FAQ for further notes. In particular, you should also set the default_sort_order (you can now use None as well as the dummy compare lambda in that example, for better performance) to ensure there is no sorting, and remove the model from the treeview for the duration of the operations.

If it's a lot of changes you may be better off creating and setting a complete new model.

这篇关于由于排序,GtkTreeView插入/更新性能损失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆