简单的任务,没有冻结gui

时间:2012-11-04 20:10:23

标签: c# multithreading backgroundworker dispatcher

我遇到了一个小问题。我有两个线程,一个执行一个循环,每次都需要返回/发送一个数字到GUI的线程。为此,我使用 BackGroundWorker ReportProgress

让我们这样说:

我有一个 BackGroundWorker 执行(DoWork)一个从0到任何数字的简单循环。循环的每个条目我使用ReportProgress事件将计数器发送到GUI的线程,该线程将打印计数器的值。

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        int count = 0;
        BackgroundWorker Worker = (BackgroundWorker)sender;

        while (count < 10000000)
        {
            Worker.ReportProgress(count);
            count++;
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        txt.Text = e.ProgressPercentage.ToString();
    }

现在,这个操作冻结了GUI。

我知道ReportProgress正在创建 BackGroundWorker 的线程中调用ProgressChange处理程序,所以我认为循环执行速度太快,因此GUI的线程没有成功将值打印为必需的。

如果不冻结GUI,我该怎么办才能执行这样的任务?

我听说过Dispatcher,但我不确定它用于什么。

3 个答案:

答案 0 :(得分:3)

问题是每次更改时都在调用reportProgress。只有在“需要”报告进度时才应调用它。请参阅MSDN http://msdn.microsoft.com/en-us/library/ka89zff4.aspx。 把你的笨蛋变成这样的东西:

 while (count < 10000000)
    {
        if ((count % 1000) == 0)
            Worker.ReportProgress(count);
        count++;
    }

这会在每1000个处理过的项目之后调用ReportProgress,因此不会给GUI线程带来不必要的负担

答案 1 :(得分:1)

您的示例代码尝试以比GUI处理更新通知消息快得多的速度更新GUI,因此使用gunge充斥GUI Windows消息队列并阻止它处理其他消息 - GUI冻结。

监视非GUI线程中高速率操作的进度是轮询是更好解决方案的少数几次之一。使用Forms.Timer事件来读取和显示'currentProgress'值,可能由线程的方法返回。 500毫秒是一个合理的计时器值 - 人类用户无法在编辑/文本框中跟上变化的整数值,速度要快得多。

'理想情况下',currentProgress值的读/写应该被锁定,也许是使用原子操作,但是如果你每500ms只读一个int,你可能甚至不需要那个'真实' '线程的功能意味着进度计数不太可能连续缓存在寄存器中。

答案 2 :(得分:0)

如何在不冻结GUID的情况下执行此类任务?

使用调度程序让我假设您正在使用WPF,无论如何,它将是:

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    int count = 0;
    BackgroundWorker Worker = (BackgroundWorker)sender;

    while (count < 10000000)
    {
        Worker.ReportProgress(count);
        count++;
    }
}

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    Dispatcher.BeginInvoke((Action)(() => { txt.Text = e.ProgressPercentage.ToString(); }));
}

调用Dispatcher.BeginInvoke会导致在UI线程上实际执行给定的Action,确保除了访问UI元素的UI线程之外的线程的原因不会引发异常。

此外,您可以尝试这样做,只是作为替代by using a task.