2009-05-08 12 views
12

मैंने हाल ही में एक परियोजना में एक दीवार मारा है जिस पर मैं काम कर रहा हूं जिस पर पीईक्यूटी का उपयोग किया जाता है। मेरे पास एक 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 बार! किसी के पास एक सुराग क्यों है?

उत्तर

3

अपने ट्री दृश्य के लिए setUniformRowHeights(true) कॉल करके देखें:

इसके अलावा, वहाँ एक सी ++ उपकरण क्यूटी प्रयोगशालाओं से modeltest कहा जाता है।

https://wiki.qt.io/Model_Test

+0

संकेत के लिए धन्यवाद, लेकिन दुर्भाग्यवश, इससे मदद नहीं मिली। इससे माता-पिता कॉल की संख्या कम हो गई, लेकिन केवल 134k कॉल तक। मॉडेल्टेस्ट के लिए, यह दिलचस्प लगता है, लेकिन मुझे नहीं पता कि पीईक्यूटी में तीसरे पक्ष के सी ++ घटकों को कैसे आयात किया जाए (मुझे इसे Google करना होगा)। लेकिन किसी भी मामले में, ऐसा लगता है कि यह मॉडल सही है, है ना? –

0

मैं PyQt5 करने के लिए अपने बहुत अच्छा उदाहरण कोड परिवर्तित और Qt5.2 के तहत भाग गया और इस बात की पुष्टि कर सकते हैं कि यह संख्या अब भी समान, यानी बेवजह विशाल हैं: मुझे यकीन है कि अगर वहाँ हालांकि अजगर के लिए कुछ न कुछ है नहीं कर रहा हूँ कॉल की संख्या यहां उदाहरण के लिए रिपोर्ट का शीर्ष भाग है, सीएमडी-ए सभी का चयन करने के लिए, एक पृष्ठ स्क्रॉल करें, छोड़ें:

 ncalls tottime percall cumtime percall filename:lineno(function) 
     1 14.880 14.880 15.669 15.669 {built-in method exec_} 
    196712 0.542 0.000 0.703 0.000 /Users/dcortes1/Desktop/scratch/treeview.py:36(parent) 
    185296 0.104 0.000 0.104 0.000 {built-in method createIndex} 
    20910 0.050 0.000 0.056 0.000 /Users/dcortes1/Desktop/scratch/treeview.py:54(data) 
    225252 0.036 0.000 0.036 0.000 {built-in method isValid} 
    224110 0.034 0.000 0.034 0.000 {built-in method internalPointer} 
    7110 0.020 0.000 0.027 0.000 /Users/dcortes1/Desktop/scratch/treeview.py:28(index)
और जबकि गणना वास्तव में अत्यधिक हैं (और मेरे पास कोई स्पष्टीकरण नहीं है), ध्यान दें कि कमटाइम मान नहीं हैं इतना बड़ा। इसके अलावा उन कार्यों को तेजी से चलाने के लिए रिकोड किया जा सकता है; उदाहरण के लिए इंडेक्स() में, "अगर नहीं self.nodes" सच है? इसी तरह, ध्यान दें कि अभिभावक() और createIndex() के लिए गणना लगभग समान हैं, इसलिए index.isValid() सत्य से अधिक अक्सर सत्य है (उचित, क्योंकि एंड-नोड्स पैरेंट नोड्स से कहीं अधिक असंख्य हैं)। उस मामले को संभालने के लिए रिकोडिंग पहले माता-पिता() cumtime को काट देगा। संपादित करें: दूसरे विचार पर, ऐसे अनुकूलन "टाइटैनिक पर डेक कुर्सियों को पुनर्व्यवस्थित कर रहे हैं"।

संबंधित मुद्दे