c# listbox 显示大量数据速度很慢,如何解决?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# listbox 显示大量数据速度很慢,如何解决?相关的知识,希望对你有一定的参考价值。

c#使用listbox加载10m以上数据,第一次显示的时候速度很慢要几分钟,cpu占用%100,如何解决这个问题?谢谢,不用考虑这种设计是否合理
具体是这样实现的:
form里有两个tabpage1和tabpage2,当前窗体默认给用户呈现的是tabpage1,listbox是在tabpage2中,通过items.add把所有数据都加入listbox,程序运行完毕后,用户从tabpage1切换到tabpage2,这个时候显示listbox所有内容的过程就很慢,要好几分钟,cpu占用达到100%。
不考虑分页,如何能使显示时间减少?

谢谢,10m的记录总字节,先不考虑分页(因为涉及到各个tabpage自动跳转功能),能否解决这个问题?

10m内容是直接从另一个程序的文本日志取过来的,循环add的速度用户可以接受,就是第一次显示很慢,只要第一次显示完成后,再怎么切换都很顺畅。

多谢各位,咱们先解决如何提高listbox第一次显示大量数据的效率?

参考技术A 用这个方法可能稍微快点,我的机子上要19秒文件8.48M
private void button1_Click(object sender, EventArgs e)

DateTime dt = DateTime.Now;
string[] strArr = File.ReadAllLines("D:\\AAAA.txt", Encoding.Default);
listBox1.DataSource = strArr;
TimeSpan ts = DateTime.Now - dt;
MessageBox.Show(ts.Seconds.ToString());
参考技术B 第一 为什么不考虑是否合理 100%不合理
解决方法
1.优化数据库
2.用存储过程写
3.分批ITEM.ADD 意思就是 你可以1M 1M的加 就比较快了
参考技术C 设计的绝对的不合理。想你这样如果100M的数据,你有没有想过数据量多大?
你这样循环ADD。时间不久才怪。最好的方式就是利用算法,一次取多少。
参考技术D 10m以上数据太多了。而且用items.add这样来增加数据循环的次太多了,如果是用来显示的用datagridview速度会提高很多。 第5个回答  2009-07-03 10m是多少?
是记录数,还是记录总字节?
如果是我,我会想办法分页。
你呈现给用户10M的记录有意义么?得看到什么时候?交互性不好,不友好!

如何在显示大量文本时加快滚动响应速度

【中文标题】如何在显示大量文本时加快滚动响应速度【英文标题】:How to speed up scrolling responsiveness when displaying lots of text 【发布时间】:2016-12-09 17:25:15 【问题描述】:

我正在尝试创建一个 Python 脚本来突出显示 .txt 文件中的特定模式。为此,我修改了一个使用 Tkinter 突出显示给定数据集的脚本。但是,我倾向于让它处理的文件大约是 10000 行,这导致滚动缓慢,因为我认为它渲染了所有内容 - 无论它是否在屏幕上(如果我是,请纠正我错误的)。是否可以更改我的代码,使其以更有效的方式呈现输出?我已经尝试寻找一种方法来做到这一点,但我自己没有找到任何东西。

我的代码如下:

from Tkinter import *

class FullScreenApp(object):
    def __init__(self, master, **kwargs):
        self.master=master
        pad=3
        self._geom='200x200+0+0'
        master.geometry("0x1+0+0".format(
            master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))
        master.bind('<Escape>',self.toggle_geom)            
    def toggle_geom(self,event):
        geom=self.master.winfo_geometry()
        print(geom,self._geom)
        self.master.geometry(self._geom)
        self._geom=geom

root = Tk()
app = FullScreenApp(root)
t = Text(root)
t.pack()

#Import file
with open('data.txt') as f:
    for line in f:
        t.insert(END, line)

#Search terms - Leave blank if not required       
search_term0 = '0xCAFE'
search_term1 = '0x0011'
search_term2 = '0x961E'
search_term3 = '0x0000'
search_term4 = ''

#Assigns highlighted colours for terms not blank
t.tag_config(search_term0, background='red')
if search_term1 != '':
    t.tag_config(search_term1, background='red')
if search_term2 != '':    
    t.tag_config(search_term2, background='red')
if search_term3 != '':
    t.tag_config(search_term3, background='red')
if search_term4 != '':
    t.tag_config(search_term4, background='red')

#Define search
#Requires text widget, the keyword, and a tag
def search(text_widget, keyword, tag):
    pos = '1.0'
    while True:
        idx = text_widget.search(keyword, pos, END)
        if not idx:
            break
        pos = '+c'.format(idx, len(keyword))
        text_widget.tag_add(tag, idx, pos)

#Search for terms that are not blank
search(t, search_term0, search_term0)
if search_term1 != '':
    search(t, search_term1, search_term1)
if search_term2 != '':
    search(t, search_term2, search_term2)
if search_term3 != '':
    search(t, search_term3, search_term3)
if search_term4 != '':
    search(t, search_term4, search_term3)

root.mainloop()

以下链接中给出了文件中的数据示例:here

非常感谢您的宝贵时间,非常感谢。

【问题讨论】:

我已更改问题的标题以反映您想要修复的内容,而不是您认为需要修复的内容。主要是因为我认为情况会相反:我认为渲染所有内容会在第一次显示时变得非常慢,但滚动速度非常快(因为它已经完成了所有渲染)但必须重新渲染每个它滚动的时间会减慢它的速度。 您的代码中的某些缩进被破坏了。 “按住时,它可能会减慢到每秒 2 或 3 行” - 只有您在问题中发布的 exact 代码?另外,文件中的每一行都长吗?我每秒可能会收到 40-50 行。 我怀疑你有一些操作系统设置限制了这一点 - 你可以用鼠标滚轮更快地滚动吗? 我拿了一个quick screencap 我的滚动。我开始用鼠标滚轮滚动,但后来我改为用箭头键滚动。 【参考方案1】:

假设 MCVE 如下:

import tkinter as tk


def create_text(text_len):
    _text = list()
    for _ in range(text_len):
        _text.append("\n".format(_))
    _text = "".join(_text)
    return _text


if __name__ == '__main__':
    root = tk.Tk()
    txt = tk.Text(root)

    txt.text = create_text(10000)
    txt.insert('end', txt.text)

    txt.pack()
    root.mainloop()

分析

基于this 我认为这不是渲染问题。我认为拥有fixed rate of registering &lt;KeyPress&gt; events 是个问题。这意味着每秒注册的事件数量是固定的,即使硬件可能能够以更快的速度注册。类似的规则也应该适用于鼠标滚动事件。


渲染解决方案

也许为txt['height'] 的缓冲区比例分割文本会有所帮助。但这不就是 Tk 应该呈现的方式吗?


渲染无关问题的解决方案

如果一个步骤将被定义为光标移动到上一行或下一行,对于每个注册的 UpDown 事件;然后scrolling_speed = step * event_register_frequency


通过增加步长

一个简单的解决方法是为键绑定的每个注册增加步长,例如增加要跳转的行数。

但是已经有这样的默认行为,假设页面长度> 1行,Page UpPage Down具有页面的步长。这使得滚动速度增加,即使事件注册率保持不变。

或者,可以定义一个具有更大步长的新事件处理程序,为 UpDown 的每次注册调用多个光标移动,例如:

import tkinter as tk


def create_text(text_len):
    _text = list()
    for _ in range(text_len):
        _text.append("\n".format(_))
    _text = "".join(_text)
    return _text


def step(event):
    if txt._step_size != 1:
        _no_of_lines_to_jump = txt._step_size
        if event.keysym == 'Up':
            _no_of_lines_to_jump *= -1

        _position = root.tk.call('tk::TextUpDownLine', txt, _no_of_lines_to_jump)
        root.tk.call('tk::TextSetCursor', txt, _position)
        return "break"

if __name__ == '__main__':
    root = tk.Tk()
    txt = tk.Text(root)

    txt.text = create_text(10000)
    txt.insert('end', txt.text)

    txt._step_size = 12
    txt.bind("<Up>", step)
    txt.bind("<Down>", step)

    txt.pack()
    root.mainloop()

通过模仿按键事件注册表率增加

正如here 中提到的,实际上修改按键注册表速率超出了 Tk 的范围。相反,它可以被模仿:

import tkinter as tk


def create_text(text_len):
    _text = list()
    for _ in range(text_len):
        _text.append("\n".format(_))
    _text = "".join(_text)
    return _text


def step_up(*event):
    _position = root.tk.call('tk::TextUpDownLine', txt, -1)
    root.tk.call('tk::TextSetCursor', txt, _position)

    if txt._repeat_on:
        root.after(txt._repeat_freq, step_up)
    return "break"


def step_down(*event):
    _position = root.tk.call('tk::TextUpDownLine', txt, 1)
    root.tk.call('tk::TextSetCursor', txt, _position)

    if txt._repeat_on:
        root.after(txt._repeat_freq, step_down)
    return "break"


def stop(*event):
    if txt._repeat_on:
        txt._repeat_on = False
        root.after(txt._repeat_freq + 1, stop)
    else:
        txt._repeat_on = True

if __name__ == '__main__':

    root = tk.Tk()

    txt = tk.Text(root)

    txt.text = create_text(10000)
    txt.insert('end', txt.text)
    txt._repeat_freq = 100
    txt._repeat_on = True

    txt.bind("<KeyPress-Up>", step_up)
    txt.bind("<KeyRelease-Up>", stop)
    txt.bind("<KeyPress-Down>", step_down)
    txt.bind("<KeyRelease-Down>", stop)

    txt.pack()
    root.mainloop()

通过增加步长和模仿注册率增加

import tkinter as tk


def create_text(text_len):
    _text = list()
    for _ in range(text_len):
        _text.append("\n".format(_))
    _text = "".join(_text)
    return _text


def step_up(*event):
    _no_of_lines_to_jump = -txt._step_size
    _position = root.tk.call('tk::TextUpDownLine', txt, _no_of_lines_to_jump)
    root.tk.call('tk::TextSetCursor', txt, _position)

    if txt._repeat_on:
        root.after(txt._repeat_freq, step_up)
    return "break"


def step_down(*event):
    _no_of_lines_to_jump = txt._step_size
    _position = root.tk.call('tk::TextUpDownLine', txt, _no_of_lines_to_jump)
    root.tk.call('tk::TextSetCursor', txt, _position)

    if txt._repeat_on:
        root.after(txt._repeat_freq, step_down)
    return "break"


def stop(*event):
    if txt._repeat_on:
        txt._repeat_on = False
        root.after(txt._repeat_freq + 1, stop)
    else:
        txt._repeat_on = True

if __name__ == '__main__':

    root = tk.Tk()

    txt = tk.Text(root)

    txt.text = create_text(10000)
    txt.insert('end', txt.text)
    txt._step_size = 1
    txt._repeat_freq = 100
    txt._repeat_on = True

    txt.bind("<KeyPress-Up>", step_up)
    txt.bind("<KeyRelease-Up>", stop)
    txt.bind("<KeyPress-Down>", step_down)
    txt.bind("<KeyRelease-Down>", stop)

    txt.pack()
    root.mainloop()

【讨论】:

它说我可以在 1 小时内提供赏金【参考方案2】:

所以这可以通过称为多线程的东西来解决。一台计算机可以同时执行多项任务,否则您的网络体验将不一样。这是一个演示多线程的简单函数

from threading import Thread

def execOnDifferentThread(funct=print, params=("hello world",)):
    t = Thread(target=funct, args=params)
    t.start()

现在请注意,这可能不是最好的示例,但现在要并行运行一个函数,您所要做的就是 execOnDifferentThread(funct=A, params=B) 其中 A 是函数名称,B 是 元组 将传递给您的函数的参数。现在,我不想为您编写代码,但是使用此功能,您可以multi-thread 代码的某些部分以使其更快。如果您真的被卡住了,只需评论在哪里并提供帮助。但是请先自己尝试,现在您已经掌握了多线程的能力

【讨论】:

另外,记住在多线程中使用全局变量时,将它们声明为全局变量 我建议线程化代码的t.insertsearch 部分

以上是关于c# listbox 显示大量数据速度很慢,如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

C# 域用户验证问题

c# winform listbox 如何 获取 当前 选中的值 急!!!

C#开发的winform程序,窗体打开的速度很慢,请高手指点。。谢了先。。。

MFC,ListBox使用 InsertColumn添加列,在列表框中却无论如何都不显示,很是郁闷,求解,正解追加高分。

C#开发的winform程序,窗体打开的速度很慢,请高手指点。。谢了先。。。

为啥在 C# 中的二维数组中按列写入速度很慢