等待x任务时间并报告进度

时间:2011-11-06 19:17:21

标签: .net wpf task wait progress

我需要一个比Thread.Sleep更好的睡眠任务设计,我正在使用Task类。

在我的wpf应用程序中运行一个任务,此任务运行另外几个任务,每个任务首先登录到Internet网站,登录后需要等待几秒钟并通知用户何时进一步这是我的问题,因为使用Thread.Sleep我无法报告进度。

还有比登录更多的功能,它大约是5-6,它们都要求一个互联网资源,而它们之间需要有一个休眠时间,剩余时间报告发送到gui,这个5-6功能都在一个任务,但可能有很多任务。

我需要的是让任务等待,但也允许它发送剩余时间的更新以继续GUI。

你对这个问题有什么想法,如何让它变得更好,也许你已经有一些设计模式来解决这个问题?

我也听说使用Thread.Sleep是一种糟糕的设计实践。

编辑:没人知道? 是什么类型的自包含计时器与线程等待waithandle,autoresetevent,任何人?

4 个答案:

答案 0 :(得分:6)

解决方案是将其视为异步回调,而不是同步等待。 如果您使用的是Async CTP,那么正确的方法是:

async item => { await Task.Delay(1000); Process(item); }

这似乎也是DataFlow或Rx的理想用例。

使用Reactive Extensions:

static void Track(int timeout, int frequency, string item)
    {
        Observable.Interval(TimeSpan.FromSeconds(frequency)) //produces 0, 1, 2.. with the interval
                  .Do(i => Console.WriteLine("Working on {0}", item)) // work on item
                  .TakeUntil(Observable.Timer(TimeSpan.FromSeconds(timeout))) //stop once the timer publishes a value
                  .Subscribe
                  (
                        i => Console.WriteLine("Reporting {0}%", ((double)(i + 1) / timeout * 100)), // the interval reaches OnNext
                        e => Console.WriteLine("Error!"), // error occured 
                        () => Console.WriteLine("Completed") // observable completed
                  );
    }

在用Track(timeout: 5, frequency: 1, item: "http://example.com/?")调用它时,产生的输出是:

Working on http://example.com/?
Reporting 20%
Working on http://example.com/?
Reporting 40%
Working on http://example.com/?
Reporting 60%
Working on http://example.com/?
Reporting 80%
Completed

答案 1 :(得分:1)

不是让一个任务执行所有这六个函数(登录等),而是让每个函数成为一个单独的任务。然后,您可以创建按时间排序的优先级队列。当您想要启动其中一个元任务时,将其第一个函数与状态数据(即URL,用户ID,密码等)一起放入队列中。

当每个函数完成时,它将对要执行的下一个函数进行排队。因此,如果前两个函数是login和get_data,那么您将拥有:

queue login with state data to execute at DateTime.Now
When login is finished, it queues get_data with the state data and DateTime.Now + 5 seconds (or whatever time)

当最后一个函数执行时,它会在某处发布结果。

然后,您可以设置一个计时器,该计时器将每秒轮询队列10次(或者只要将某些内容添加到队列中,就会更新计时器的下一个计时时间)。它可以根据需要启动单个任务。

新的Async CTP可能已经有了这样的事情:“执行任务”。可能值得研究。

至于报告进度,每个功能都可以在启动时报告进度(即“登录”......“等待5秒获取数据”......“获取数据”等)如果您愿意,可以使计时器线程定期遍历优先级队列并报告何时将执行特定任务。虽然这可能有点过头了。

你听到的是正确的:Thread.Sleep是一个非常糟糕的主意,特别是当你使用线程池线程时。

答案 2 :(得分:1)

忘记使用Thread.Sleep。相反,在后台线程中运行您的任务并使用带有AutoResetEvent的WaitHandle。 (链接:WaitHandle/WaitOne / AutoReset

您的后台线程可以使用异步委托向UI发送更新,但调用线程将等待它,直到发生任何事情:

1)您的线程使用yourwaithandle.Set();报告它已完成任务。

2)等待的线程超时(超时值被设置为WaitOne()-method的参数。

答案 3 :(得分:0)

您是否考虑过使用Timer(来自System.Timers)来执行插页式“剩余时间”消息更新?您的每个任务都可以设置预期的完成时间值,然后您的计时器任务可以负责根据需要倒计时和更新UI。不需要Thread.Sleep,Timer将在线程池线程上执行其Tick代码。