2017-05-03 29 views
1

我们正在开发一个使用SWT的Java应用程序,它提供了虚拟表。在Windows和OSX上,允许在100到10M之间切换表行数的测试代码在100ms以内,但在Ubuntu 16.04上需要几秒钟。现在我们想知道这是SWT的GTK实现还是GTK本身的缺点?在后一种情况下,GTK 2和GTK 3有区别吗?GTK 2/3是否支持高效的虚拟表?

回答

3

TLDR:不幸的是,GTK的GtkTreeView似乎并不支持虚拟模式可言的,它的方式,对大量的项目非常低效的实现。 SWT选择使用GtkTreeView执行Table,并引入了更多性能问题。

SWT Table.setItemCount()

来源为Table.setItemCount()

  • 库:http://git.eclipse.org/gitroot/platform/eclipse.platform.swt.git
  • 源文件:eclipse.platform.swt\bundles\org.eclipse.swt\Eclipse SWT\gtk\org\eclipse\swt\widgets\Table.java
  • 查找:public void setItemCount (int count) {

你会看到,即使在VIRTUAL模式,setItemCount将分配的所有项目,一次一个,使用OS.gtk_list_store_append()

for (int i=itemCount; i<count; i++) { 
    OS.gtk_list_store_append (modelHandle, iter); 
} 

SWT OS.gtk_list_store_append

来源为OS.gtk_list_store_append

  • 储存库:http://git.eclipse.org/gitroot/platform/eclipse.platform.swt.git
  • 源文件:eclipse.platform.swt\bundles\org.eclipse.swt\Eclipse SWT\gtk\org\eclipse\swt\widgets\Table.java
  • 查找:public static final void gtk_list_store_append(long /*int*/ list_store, long /*int*/ iter) {

这里,每个项目一锁获取和释放和本地方法被调用。我想他们应该至少用一个本地电话分配所有项目。

public static final void gtk_list_store_append(long /*int*/ list_store, long /*int*/ iter) { 
    lock.lock(); 
    try { 
     _gtk_list_store_append(list_store, iter); 
    } finally { 
     lock.unlock(); 
    } 
} 

GTK gtk_list_store_append

  • 库:git://git.gnome.org/gtk+
  • 源文件:gtk/gtkliststore.c
  • 查找:gtk_list_store_append (GtkListStore *list_store,

它只是调用gtk_list_store_insert(list_store, iter, -1)

GTK gtk_list_store_insert

  • 库:git://git.gnome.org/gtk+
  • 源文件:gtk/gtkliststore.c
  • 查找:gtk_list_store_insert (GtkListStore *list_store,

的关键作用是g_sequence_insert_before是插入到一个gsequence,这是一个平衡的树。

void 
gtk_list_store_insert (GtkListStore *list_store, 
       GtkTreeIter *iter, 
       gint   position) 
{ 
    GtkListStorePrivate *priv; 
    GtkTreePath *path; 
    GSequence *seq; 
    GSequenceIter *ptr; 
    gint length; 

    g_return_if_fail (GTK_IS_LIST_STORE (list_store)); 
    g_return_if_fail (iter != NULL); 

    priv = list_store->priv; 

    priv->columns_dirty = TRUE; 

    seq = priv->seq; 

    length = g_sequence_get_length (seq); 
    if (position > length || position < 0) 
    position = length; 

    ptr = g_sequence_get_iter_at_pos (seq, position); 
    ptr = g_sequence_insert_before (ptr, NULL); 

    iter->stamp = priv->stamp; 
    iter->user_data = ptr; 

    g_assert (iter_is_valid (iter, list_store)); 

    priv->length++; 

    path = gtk_tree_path_new(); 
    gtk_tree_path_append_index (path, position); 
    gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter); 
    gtk_tree_path_free (path); 
} 

不幸的是,这个函数很多事情是不是一个大容量插入期间必要,例如它计算序列的长度(其具有非平凡的时间复杂度)每次转换索引来迭代器,火灾更新通知的树,等等等等

我搜索,但没有发现对于批量插入任何东西。

Windows实现

Windows实现的Table使用OS提供的ListView控制,其有效地用于虚拟模式下实现(见LVS_OWNERDATA

参见:Eclipse Bug 236863