मैंने हाल ही में एक परियोजना में एक दीवार मारा है जिस पर मैं काम कर रहा हूं जिस पर पीईक्यूटी का उपयोग किया जाता है। मेरे पास एक QTreeView है जो QAbstractItemModel पर लगा हुआ है जिसमें आम तौर पर हजारों नोड्स होते हैं। अब तक, यह ठीक काम करता है, लेकिन मुझे आज एहसास हुआ कि बहुत सारे नोड्स का चयन करना बहुत धीमा है। कुछ खुदाई के बाद, यह पता चला है कि QAbstractItemModel.parent() को अक्सर रास्ता कहा जाता है।QTreeView में धीमे चयन, क्यों?
#!/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()
समस्या को पुन: करने के लिए, बस कोड को चलाने (जो रूपरेखा करता है) और पेड़ विजेट में सभी नोड्स (या तो पारी चयन या Cmd-ए के माध्यम से) का चयन करें: मैं समस्या पुन: पेश करने में कम से कम कोड बनाया। जब आप एप्लिकेशन से बाहर निकलने, रूपरेखा आँकड़े की तरह कुछ दिखाएगा:
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}
इस डेटा में अजीब हिस्सा कितनी बार माता-पिता() कहा जाता है: 2k नोड्स के लिए 136k बार! किसी के पास एक सुराग क्यों है?
संकेत के लिए धन्यवाद, लेकिन दुर्भाग्यवश, इससे मदद नहीं मिली। इससे माता-पिता कॉल की संख्या कम हो गई, लेकिन केवल 134k कॉल तक। मॉडेल्टेस्ट के लिए, यह दिलचस्प लगता है, लेकिन मुझे नहीं पता कि पीईक्यूटी में तीसरे पक्ष के सी ++ घटकों को कैसे आयात किया जाए (मुझे इसे Google करना होगा)। लेकिन किसी भी मामले में, ऐसा लगता है कि यह मॉडल सही है, है ना? –