pyqt5 qlistwidget 对大文本数据的性能

Posted

技术标签:

【中文标题】pyqt5 qlistwidget 对大文本数据的性能【英文标题】:pyqt5 qlistwidget performance with large text data 【发布时间】:2019-01-25 03:18:54 【问题描述】:

我正在编写一个 pyqt5 GUI 应用程序来解析具有以下结构的特定日志文件。每一行已经被拆分为列表中的字符串并存储为 self.calls。此列表存储大约 60K 行数据。

目标是使用用户输入字符串进行搜索,找到所有在该行中有输入字符串的呼叫 ID(1、2、3 等)。然后找到与该呼叫 ID 相关的所有消息并使用 qlistwidget 按顺序显示它们(我喜欢 Qlistwidget 的简洁外观。我尝试过 Qplaintext,但只显示 self.calls 需要很长时间)

我有一个 qlineedit 来收集用户输入 我接受该输入,使用正则表达式在 self.calls 中查找与用户输入匹配的每个项目 再次使用正则表达式查找所有呼叫 ID 号(与用户输入匹配的行)并将它们放在一个列表中 然后使用 for 循环将具有该调用 ID 的所有行添加到 qlistwidget

我可以使用 qlistwidget addItem 和一个简单的 for 循环来显示 self.calls 中的所有 50K 行,这需要几秒钟(可以接受)。

for call in self.calls:
        self.output.addItem(call)

我的问题是当我实现我的搜索功能时,如果有大量的行匹配,应用程序会很糟糕并且需要很长时间才能显示数据,即使它是来自 self.calls 数据的较小子集。我尝试使用带有条件的嵌套 for 循环、列表理解和带有正则表达式的 for 循环。全部执行大致相同,10K 行解析数据可能需要 20-30 秒。

希望有人能给我指点使用 qlistwidget 更快地显示数据的方法。

数据:

Oct 12 18:38:34 user.info server1 host:server:  INFO : call 1: allocated for "Web client" conference participation
Oct 12 18:38:34 user.info server1 host:server:  INFO : call 1: setting up combined RTP session for DTLS (combined media and control)
Oct 12 18:38:34 user.info server1 host:server:  INFO : call 1: starting DTLS combined media negotiation (as initiator)
Oct 12 18:38:35 user.info server1 host:server:  INFO : call 1: completed DTLS combined media negotiation
Oct 12 18:38:35 user.info server1 host:server:  INFO : call 1: media framework reporting rx video RTP frequency 0 - fixed up to 90000
Oct 12 18:38:35 user.info server1 host:server:  INFO : call 1: starting DTLS combined media negotiation (as initiator)
Oct 12 18:38:36 user.info server1 host:server:  INFO : call 1: completed DTLS combined media negotiation
Oct 12 18:38:59 user.info server1 host:server:  INFO : call 1: tearing down (conference media)
Oct 12 18:51:27 user.info server1 host:server:  INFO : call 2: recognised as Avaya
Oct 12 18:51:27 user.info server1 host:server:  INFO : call 2: incoming SIP audio call from
Oct 12 18:51:40 user.info server1 host:server:  INFO : call 3: outgoing encrypted SIP call to 
Oct 12 18:51:40 user.info server1 host:server:  INFO : call 3: setting up peer to peer media instantiation
Oct 12 18:51:40 user.info server1 host:server:  INFO : call 3: setting up UDT RTP session for DTLS (combined media and control)
Oct 12 18:51:40 user.info server1 host:server:  INFO : call 3: SIP call ringing
Oct 12 18:51:40 user.info server1 host:server:  INFO : call 3: determined far end good lip sync status, 1
Oct 12 18:51:42 user.info server1 host:server:  INFO : call 3: remote layout version supported by peer now 6
Oct 12 18:51:44 user.info server1 host:server:  INFO : call 4: allocated for "Web client" conference participation
Oct 12 18:51:44 user.info server1 host:server:  INFO : call 4: setting up combined RTP session for DTLS (combined media and control)
Oct 12 18:51:44 user.info server1 host:server:  INFO : call 4: starting DTLS combined media negotiation (as initiator)
Oct 12 18:51:44 user.info server1 host:server:  INFO : call 4: completed DTLS combined media negotiation
Oct 12 18:52:47 user.info server1 host:server:  INFO : call 3: ending; local teardown - connected for 1:07

代码:

if len(self.searchbar.text()) > 2:

    self.output_filtered.setHidden(False)

    #Regex compiles
    re_searchstring = re.compile(r"(^.*?%s.*?$)" % self.searchbar.text(), re.IGNORECASE)
    re_callindex = re.compile(r"call\s(\d+):")

    #Get results of all calls matching searchbar input
    result = list(filter(re_searchstring.match, self.calls))

    #Build a temp list with call index number
    call_list_temp = []
    for item in result:
        callindex = re_callindex.findall(item)
        call_list_temp.append(callindex)
    #Merge the call list, remove dups, and sort
    call_list_temp = list(itertools.chain(*call_list_temp))
    call_list = list(OrderedDict.fromkeys(call_list_temp))

    ##############################
    # For loops with conditional
    for index in call_list:
        for calls in self.calls:
            if "call " + str(index) + ":" in calls:
                self.output_filtered.addItem(calls)

    # List Comprehension
    test = [calls for index in call_list for calls in self.calls if "call " + str(index) + ":" in calls]
    for call in test:
        self.output_filtered.addItem(call)

    # For loops with regex
    for index in call_list:
        re_callfinder = re.compile(r"(^.*call\s%s.*$)" % index)
        for item in self.calls:
            call = re_callfinder.findall(item)
            for line in call:
                self.output_filtered.addItem(line)

【问题讨论】:

【参考方案1】:

您可以切换到Model/View system,并使用QListView 代替QListWidget。这样您就可以利用专为此类工作设计的 QModel 类...

【讨论】:

感谢您的建议,但切换到 QListView 与 Qstandarditem 的处理时间相同。我已经开始尝试在 GUI 上显示它,而是将其卸载到文本文件中。

以上是关于pyqt5 qlistwidget 对大文本数据的性能的主要内容,如果未能解决你的问题,请参考以下文章

如何在pyqt5 QlistWidget中选择当前项目

PyQt5 QListWidget自定义项目[重复]

PyQt5:当列表失去焦点时设置 QListWidget 选择颜色

如何在 PyQt5 中返回 QlistWidget 中项目的值

PyQt5 检查项目是不是已经在 QListWidget

获取 QListWidget PyQt5 中所选项目的名称