如果我不在 WinForms 上使用 Thread.Sleep,BackgroundWorker 将不起作用

Posted

技术标签:

【中文标题】如果我不在 WinForms 上使用 Thread.Sleep,BackgroundWorker 将不起作用【英文标题】:BackgroundWorker isn't working if I don't use Thread.Sleep on WinForms 【发布时间】:2021-11-24 02:47:35 【问题描述】:

这是我的简单代码:

private void button1_Click(object sender, EventArgs e)

    if (backgroundWorker1.IsBusy) return;
    backgroundWorker1.RunWorkerAsync();


private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

    var worker = sender as BackgroundWorker;

    for (var i = 1; i <= 10000; i++)
    
        Thread.Sleep(1);
        worker?.ReportProgress(i);
    


private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

    label1.Text = e.ProgressPercentage.ToString();


private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    label1.Text = "Completed.";

此代码可以正常工作。但是如果我从代码中删除Thread.Sleep(1);,BackgroundWorker 将不起作用。这么简单的事情我都找不到错误的来源。

【问题讨论】:

不起作用是什么意思?如果你删除了 Sleep,你会用太多的连续更新来淹没 UI 线程。它不能像空的 for 循环那样快速更新。 @Steeeve - 可以这么说。我怎么知道?事实是:1000 条记录来自数据库。我将它们添加到对象列表中,并显示在 Gridview 中。在这种情况下也会发生同样的事情。 不知道真正的代码我不能说太多。但是,在 GridView 中显示 1000 条记录可能比从数据库中获取它们需要更多时间。 【参考方案1】:

没有必要这么频繁地报告进度。

做这样的事情:

for (var i = 1; i <= 10000; i++)

    Thread.Sleep(1);
    if (i % 100 == 0)
    
        worker?.ReportProgress(i);
    

或者您可以检查时间或滴答计数,当您看到 50 毫秒的时间已经过去时,请执行 ReportProgress。比这更频繁是没有意义的。

此外,您可以批量更新您的 GridView,以提高效率/减少浪费 - 一次发送这么多行 1 行将会产生更多开销。

【讨论】:

以上是关于如果我不在 WinForms 上使用 Thread.Sleep,BackgroundWorker 将不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如果我不想加载主窗体,如何处理 Winforms 中的命令行参数?

Winforms:如何加速 Invalidate()?

如果你在一个不在线程池中的线程中等待会发生啥?

thread_local unordered_map 加上 AccessibleObjectFromWindow 不在 WinXP 中运行

c# WebBrowser DocumentText 工作一次但不在循环中?

SQL注入在winforms中有效吗?