Per*_*xus 2 c# wpf task-parallel-library
我有一个主线程,包含我的WPF GUI和一个或多个后台线程,偶尔需要异步执行主线程中的代码(例如GUI中的状态更新).
有两种方法(我知道,可能更多)来实现这一目标:
TaskScheduler目标线程的同步上下文来调度任务,以及Dispatcher目标线程调用委托.在代码中:
using System.Threading.Tasks;
using System.Threading;
Action mainAction = () => MessageBox.Show(string.Format("Hello from thread {0}", Thread.CurrentThread.ManagedThreadId));
Action backgroundAction;
// Execute in main thread directly (for verifiying the thread ID)
mainAction();
// Execute in main thread via TaskScheduler
var taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
backgroundAction = () => Task.Factory.StartNew(mainAction, CancellationToken.None, TaskCreationOptions.None, taskScheduler);
Task.Factory.StartNew(backgroundAction);
// Execute in main thread via Dispatcher
var dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
backgroundAction = () => dispatcher.BeginInvoke(mainAction);
Task.Factory.StartNew(backgroundAction);
Run Code Online (Sandbox Code Playgroud)
我喜欢基于TPL的版本,因为我已经使用了很多TPL,它为我提供了很多灵活性,例如通过等待任务或将其与其他任务联系起来.但是,在迄今为止我看到的WPF代码的大多数示例中,使用了Dispatcher变体.
假设我不需要任何灵活性并且只想在目标线程中执行一些代码,那么一个人比另一个更喜欢一种方式的原因是什么?是否有任何性能影响?
我强烈建议您阅读基于任务的异步模式文档.这将允许你组织你的API来准备时async,并await上街游行.
我曾经使用TaskScheduler排队更新,类似于你的解决方案(博客文章),但我不再推荐这种方法.
TAP文档有一个简单的解决方案,可以更优雅地解决问题:如果后台操作想要发布进度报告,那么它需要一个类型的参数IProgress<T>:
public interface IProgress<in T> { void Report(T value); }
Run Code Online (Sandbox Code Playgroud)
然后提供基本实现相对简单:
public sealed class EventProgress<T> : IProgress<T>
{
private readonly SynchronizationContext syncContext;
public EventProgress()
{
this.syncContext = SynchronizationContext.Current ?? new SynchronizationContext();
}
public event Action<T> Progress;
void IProgress<T>.Report(T value)
{
this.syncContext.Post(_ =>
{
if (this.Progress != null)
this.Progress(value);
}, null);
}
}
Run Code Online (Sandbox Code Playgroud)
(SynchronizationContext.Current基本上TaskScheduler.FromCurrentSynchronizationContext不需要实际的Tasks).
Async CTP包含IProgress<T>和Progress<T>类似于EventProgress<T>上面的类型(但性能更高).如果您不想安装CTP级别的东西,那么您可以使用上面的类型.
总而言之,有四种选择:
IProgress<T> - 这是将来编写异步代码的方式.它还会强制您将后台操作逻辑与UI/ViewModel更新代码分开,这是一件好事.TaskScheduler - 不是一个糟糕的方法; 这是我在切换之前使用了很长时间IProgress<T>.但是,它不会强制UI/ViewModel更新代码超出后台操作逻辑.SynchronizationContext- TaskScheduler通过鲜为人知的API具有相同的优点和缺点.Dispatcher- 真的不能推荐这个!考虑更新ViewModel的后台操作 - 因此进度更新代码中没有特定于UI的操作.在这种情况下,Dispatcher只需将ViewModel绑定到UI平台即可.讨厌.PS如果您确实选择使用Async CTP,那么IProgress<T>我的Nito.AsyncEx库中还有一些其他实现,包括一个(PropertyProgress)发送进度报告INotifyPropertyChanged(通过切换回UI线程后SynchronizationContext).
| 归档时间: |
|
| 查看次数: |
3590 次 |
| 最近记录: |