Geçenlerde hangi üzerinde çalıştığım bir projede bir duvara isabet ettik PyQT kullanır. Bir QTreeView tipik içinde düğümlerin binlerce olan bir QAbstractItemModel bağladım var. Şimdiye kadar, iyi çalışıyor, ama bugün çok fazla düğüm seçmenin çok yavaş olduğunu fark ettim. Bazı kazılardan sonra, QAbstractItemModel.parent() yönteminin çok sık çağrıldığı ortaya çıkıyor.QTreeView'da yavaş seçim, neden?
#!/usr/bin/env python
import sys
import cProfile
import pstats
from PyQt4.QtCore import Qt, QAbstractItemModel, QVariant, QModelIndex
from PyQt4.QtGui import QApplication, QTreeView
# 200 root nodes with 10 subnodes each
class TreeNode(object):
def __init__(self, parent, row, text):
self.parent = parent
self.row = row
self.text = text
if parent is None: # root node, create subnodes
self.children = [TreeNode(self, i, unicode(i)) for i in range(10)]
else:
self.children = []
class TreeModel(QAbstractItemModel):
def __init__(self):
QAbstractItemModel.__init__(self)
self.nodes = [TreeNode(None, i, unicode(i)) for i in range(200)]
def index(self, row, column, parent):
if not self.nodes:
return QModelIndex()
if not parent.isValid():
return self.createIndex(row, column, self.nodes[row])
node = parent.internalPointer()
return self.createIndex(row, column, node.children[row])
def parent(self, index):
if not index.isValid():
return QModelIndex()
node = index.internalPointer()
if node.parent is None:
return QModelIndex()
else:
return self.createIndex(node.parent.row, 0, node.parent)
def columnCount(self, parent):
return 1
def rowCount(self, parent):
if not parent.isValid():
return len(self.nodes)
node = parent.internalPointer()
return len(node.children)
def data(self, index, role):
if not index.isValid():
return QVariant()
node = index.internalPointer()
if role == Qt.DisplayRole:
return QVariant(node.text)
return QVariant()
app = QApplication(sys.argv)
treemodel = TreeModel()
treeview = QTreeView()
treeview.setSelectionMode(QTreeView.ExtendedSelection)
treeview.setSelectionBehavior(QTreeView.SelectRows)
treeview.setModel(treemodel)
treeview.expandAll()
treeview.show()
cProfile.run('app.exec_()', 'profdata')
p = pstats.Stats('profdata')
p.sort_stats('time').print_stats()
sadece kod çalıştırmasına Sorunu yeniden oluşturmak için (profilleme etmez) ve (ya vardiya seçimi veya Cmd-A üzerinden) ağaç widget'ı tüm düğümleri seçmek: Ben sorunu yeniden minimal kod yarattı. Uygulamayı çıktığınızda, profilleme istatistikler gibi bir şey gösterecektir:
Fri May 8 20:04:26 2009 profdata
628377 function calls in 6.210 CPU seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 4.788 4.788 6.210 6.210 {built-in method exec_}
136585 0.861 0.000 1.182 0.000 /Users/hsoft/Desktop/slow_selection.py:34(parent)
142123 0.217 0.000 0.217 0.000 {built-in method createIndex}
17519 0.148 0.000 0.164 0.000 /Users/hsoft/Desktop/slow_selection.py:52(data)
162198 0.094 0.000 0.094 0.000 {built-in method isValid}
8000 0.055 0.000 0.076 0.000 /Users/hsoft/Desktop/slow_selection.py:26(index)
161357 0.047 0.000 0.047 0.000 {built-in method internalPointer}
94 0.000 0.000 0.000 0.000 /Users/hsoft/Desktop/slow_selection.py:46(rowCount)
404 0.000 0.000 0.000 0.000 /Users/hsoft/Desktop/slow_selection.py:43(columnCount)
94 0.000 0.000 0.000 0.000 {len}
1 0.000 0.000 6.210 6.210 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
bu verilerdeki garip kısmı denir ne sıklıkta ebeveyn() 'dir: 136K kez 2k düğümleri için! Herkesin neden bir ipucu var? senin ağaç görünümü için setUniformRowHeights(true)
çağıran
ipucu için teşekkürler, ama ne yazık ki, yardım etmedi. Ebeveyn çağrılarının sayısını azalttı, ancak sadece 134k çağrılarına. Modeltest gelince , bu ilginç görünüyor, ama ben (ben onu google gerekecek) PyQt'de 3. parti C++ bileşenleri almak için nasıl bilmiyorum. Ama her durumda, bu modelin doğru olduğu anlaşılıyor, değil mi? –