我有一个使用TaskCompletionSource包装回调的方法,如下所示:
public Task<int> TestMethod(int argument)
{
var tcs = new TaskCompletionSource<int>();
var task = tcs.Task;
LegacyMethodWithCallback(argument, (returnValue) => tcs.TrySetResult(returnValue));
return task;
}然后我等待着这个方法:
async int CallingMethod()
{
var returnValue = await TestMethod(5);
Console.WriteLine(returnValue);
return returnValue;
}编辑: LegacyMethodWithCallback是一种使用网络与服务器通信的方法。回调运行在属于我们的专有线程池的线程上(这是实现自定义SynchronizationContext的一个原因)。自定义SynchronizationContext基本上是空白的,除了它的Post方法将委托排队到out线程池之外。下面是SC的实现,当Post被调用时,应该演示:
internal class ServiceSynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine("Post " + d + ": " + state + " for " + this.serviceLogic.ServiceLogicId);
// Enqueue the delegate into our thread pool
}
}我已经实现了自己的同步上下文,但是我被告知,CallingMethod似乎立即在调用TrySetResult的同一个线程上恢复(因此,也就是调用回调的同一个线程)。我最初预计续集将通过SynchronizationContext发布。
这种行为是否得到保证,或者是否存在调用SynchronizationContext (或任何其他线程)的情况?如果这个行为不是完全确定性的,我可以控制它吗?
在CallingMethod恢复时,我彻底检查了调用堆栈,并且似乎甚至没有考虑到SynchronizationContext (但仍然有一些代码很难被检查),因此这种行为似乎是有内嵌保证的。我说的对吗?
发布于 2016-06-08 08:24:45
这种行为是否得到保证,或者是否存在调用SynchronizationContext (或任何其他线程)的情况?
如果存在SynchronizationContext,则等待代码总是使用它(除非ConfigureAwait(false)另有规定)。这意味着,如果无法控制等待的代码,则不能假设等待代码将在线程上运行。
有几个原因,您的连续性,不内联在同一线程。一个是是否使用TaskCreationOptions.RunContinuationsAsynchronously。其他如当前的SynchronizationContext和TaskScheduler都在IsValidLocationForInlining中。
internal static bool IsValidLocationForInlining
{
get
{
// If there's a SynchronizationContext, we'll be conservative and say
// this is a bad location to inline.
var ctx = SynchronizationContext.CurrentNoFlow;
if (ctx != null && ctx.GetType() != typeof(SynchronizationContext)) return false;
// Similarly, if there's a non-default TaskScheduler, we'll be conservative
// and say this is a bad location to inline.
var sched = TaskScheduler.InternalCurrent;
return sched == null || sched == TaskScheduler.Default;
}
}https://stackoverflow.com/questions/37695275
复制相似问题