0

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

让我们这样说:

我有一个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,但我不确定它的用途。

4

3 回答 3

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 线程带来不必要的负载

于 2012-11-04T20:16:47.273 回答
1

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

在非 GUI 线程中监视高速操作的进度是少数情况下轮询是更好的解决方案之一。使用 Forms.Timer 事件读取并显示“currentProgress”值,该值可能由线程的方法返回。500ms 是一个合理的计时器值——人类用户无法以比这快得多的速度跟上编辑/文本框中不断变化的整数值。

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

于 2012-11-05T10:09:49.933 回答
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 会导致给定的 Action 在 UI 线程上实际执行,确保不会因 UI 线程访问 UI 元素之外的线程的原因而引发异常。

此外,您可以尝试这样做,作为使用任务的替代方法。

于 2012-11-04T20:19:04.137 回答