今天用.NET 4.5中的TPL的特性做了个小例子,实现了WPF的进度条progressbar,运行时间elapse time和等待spinner。
先上图吧。
这个例子包含4个实现,分别是同步版本(Sync),异步版本(Async),并发版本(Parallel)和通过数据绑定实现的并发版本(Parallel with Data Binding)。代码放在了Github上。其中Spinner的实现来源于stackoverflow上Drew Noakes提供的代码。
1. 同步版本(Sync)
这个版本中进度条、运行时间都不能更新,而且用户不能取消,因为所有的工作都是在UI线程中做的,整个UI被阻塞了。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 | internal override void Start() { startWaiting(); for (int i = 1; i <= Job.JobNumber; i++) { Job.TimeConsumingJob(); m_FinishedJob++; m_Progressbar.Value = m_FinishedJob; } stopWaiting(); } |
2. 异步版本(Async)
使用C#的await
和
async关键字实现异步调用,这样进度条、运行时间都可以更新了,而且用户可以取消,因为UI没有被阻塞。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | internal override async void Start() { startWaiting(); try { for (int i = 1; i <= Job.JobNumber; i++) { await Task.Factory.StartNew(Job.TimeConsumingJob, m_CancellationTokenSource.Token); m_FinishedJob++; m_Progressbar.Value = m_FinishedJob; } } catch (OperationCanceledException) { m_CancellationTokenSource = new CancellationTokenSource(); } stopWaiting(); } |
3. 并发版本(Parallel)
把后台的工作都并发处理了,除了不阻塞UI之外处理速度得到了提高。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | internal override async void Start() { startWaiting(); List<Task> taskList = new List<Task>(); for (int i = 1; i <= Job.JobNumber; i++) { taskList.Add( Task.Factory.StartNew(Job.TimeConsumingJob).ContinueWith(t => { m_FinishedJob++; m_Progressbar.Value = m_FinishedJob; }, m_CancellationTokenSource.Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()) ); } try { await Task.WhenAll(taskList); } catch (OperationCanceledException) { m_CancellationTokenSource = new CancellationTokenSource(); } stopWaiting(); } |
4. 通过数据绑定实现的并发版本(Parallel with Data Binding)
一样是并发,但是用了Data Binding,没有直接操作UI控件。