【发布时间】:2016-05-30 21:05:00
【问题描述】:
给定我已经拥有的SynchronizationContext(基本上是一个特定线程的窗口),我如何创建发布到此上下文的Tasks?
作为参考,这里有一个非常基本的演示如何设置SynchronizationContext。
public class SomeDispatcher : SynchronizationContext
{
SomeDispatcher() {
new Thread(() => {
SynchronizationContext.SetSynchronizationContext(this);
// Dispatching loop (among other things)
}).Start();
}
override void Post(SendOrPostCallback d, object state)
{
// Add (d, state) to a dispatch queue;
}
}
这适用于已经在上下文中运行的 async / await。
现在,我希望能够从外部上下文(例如,从 UI 线程)向此发布 Tasks,但似乎找不到这样做的干净方法。
一种方法是使用TaskCompletionSource<>。
Task StartTask(Action action)
{
var tcs = new TaskCompletionSource<object>();
SaidDispatcher.Post(state => {
try
{
action.Invoke();
tcs.SetResult(null);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return tcs.Task;
});
但这是在重新发明轮子,并且支持诸如 StartNew(Func<TResult>)、StartNew(Func<Task<TResult>>) 等变体的主要痛苦。
SynchronizationContext 的 TaskFactory 接口可能是理想的,但我似乎无法干净地实例化一个:
TaskFactory CreateTaskFactory()
{
var original = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(SomeDispatcher); // yuck!
try
{
return new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
}
finally
{
SynchronizationContext.SetSynchronizationContext(original);
}
}
(即必须临时处理当前线程的同步上下文似乎很麻烦。)
【问题讨论】:
-
如何通过复制现有 SynchronizationContextTaskScheduler 的逻辑来实现自定义 TaskScheduler?当然不需要复制,逻辑本身看起来很简单。
-
@Evk 有几个
internals 你不能使用,但主要思想仍然存在——你需要自己的TaskScheduler。 -
为什么要将任务发布到同步上下文?同步上下文的通常用途是从同步上下文开始。
-
@antak:如果你只想要一个单线程的syncctx/taskfactory,那么你可能会发现我的AsyncContextThread 类型很有帮助。
标签: c# async-await