2011-04-02 69 views
1

我正试图实现此处显示的MSDN异步模式示例:http://msdn.microsoft.com/en-us/library/8wy069k1%28v=VS.90%29.aspx。在该示例中,ProgressChanged事件的触发频率等于UI在处理事件时挂起。请注意,我改变了:使用C#异步模式更新UI时出现问题

int testNumber = rand.Next(200000); 

int testNumber = 20000000; 

startAsyncButton_Click更好地测试了这种情况。

进度栏确实按预期进行更新,但所有其他UI事件都已挂起。如果我在BuildPrimeNumberList方法改变

// Yield the rest of this time slice. 
Thread.Sleep(0); 

// Yield the rest of this time slice. 
Thread.Sleep(1); 

,该UI开始响应位这违背使用线程的性能的目的。

任何人都可以推荐一种方法,有效地让用户界面在这个例子中保持响应吗?

谢谢

+0

多线程的这种用法是不是真正的性能,它是关于无锁定UI进行长时间运行的操作。在性能可能非常关键(非常罕见)的现实世界中,您可以更简单地更新UI。 – AndrewS 2011-04-02 03:40:06

回答

1

这是MSDN上一个令人误解的例子。对于在后台线程上执行工作并保持活动状态并通知后台进度的场景,请使用BackgroundWorker类。 http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

+0

因此,对于我的教育,它是如何误导。此外,在什么情况下你会使用文章中描述的模式与背景工作者类? – dtrain 2011-04-02 03:45:30

+1

我会使用基于事件的模型或IAsyncResult模型(第三个选项)在后台执行单个操作,如调用Web服务。对于长时间运行或多操作任务,backgroundworker是专门为此目的而创建的。 – 2011-04-02 03:55:22

0

在这种情况下,或者报告进度妨碍了实际工作的任何其他情况下,关键是报告进度不太频繁,或者至少限制尝试的UI更新量。

此示例已经有一个机制:progressInterval值确定进度事件导致UI更新的频率。我敢打赌,这里的问题是每100次报告的进度仍然过多。

而不是报告每X次重复(这将不随着处理器功率的增加而扩展),将DateTime存储在每个UI更新上可能会更好,然后忽略再次更新UI,直到至少250- 500ms已经过去了。

+0

更改Thread.Sleep(1)完成。它可以防止事件频繁发生。更改时间间隔仍会导致UI挂起 – dtrain 2011-04-02 03:52:40

1

注意从例如

// This event handler updates the ListView control when the 
    // PrimeNumberCalculator raises the ProgressChanged event. 
    // 
    // On fast computers, the PrimeNumberCalculator can raise many 
    // successive ProgressChanged events, so the user interface 
    // may be flooded with messages. To prevent the user interface 
    // from hanging, progress is only reported at intervals. 
    private void primeNumberCalculator1_ProgressChanged(
     ProgressChangedEventArgs e) 
    { 

    } 

的意见,我觉得你的电脑是如此之快是生产过多的事件。

尝试改变报告间隔:

private int progressInterval = 100; 

private int progressInterval = 1000; 
+0

将BuildPrimeNumberList中的Thread.Sleep更改为Thread.Sleep(1)可以通过防止事件被频繁触发来完成。改变时间间隔不会。用户界面仍然挂起 – dtrain 2011-04-02 03:55:01

+0

尝试使它更大,10000。如果这不起作用;在primeNumberCalculator1_ProgressChanged尝试放回去;作为第一行,应该绕过UI更新,看看它是否仍然挂起程序。如果是这样,您可能需要扼制链上的事件(例如asyncOp.Post(this.onProgressReportDelegate,e);) – djeeg 2011-04-02 04:14:25