C# TaskCompletionSource.TrySetResult上的同步或异步继续?
如何判断由启动的延续是同步执行还是异步执行 例如:C# TaskCompletionSource.TrySetResult上的同步或异步继续?,c#,multithreading,asynchronous,task-parallel-library,async-await,C#,Multithreading,Asynchronous,Task Parallel Library,Async Await,如何判断由启动的延续是同步执行还是异步执行 例如: // class A void RegisterNotification(TaskCompletionSource<object> tcs) { this.source.NotificationEvent += (s, eData) => { Debug.WriteLine("A.before"); tcs.TrySetResult(eData.Result);
// class A
void RegisterNotification(TaskCompletionSource<object> tcs)
{
this.source.NotificationEvent += (s, eData) =>
{
Debug.WriteLine("A.before");
tcs.TrySetResult(eData.Result);
Debug.WriteLine("A.after");
DoProcessingA();
};
}
// class B
async Task RequestNotificationAsync()
{
var tcs = new TaskCompletionSource<object>();
this.a.RegisterNotification(tcs);
Debug.WriteLine("B.before");
var data = await tcs.Task;
Debug.WriteLine("B.after");
DoProcessingB();
}
也就是说,wait tcs.Task
continuation是异步执行的。如果在相同的同步上下文上触发(或者如果两个位置都没有同步上下文),则输出将为:
B.before
A.before
A.after
B.after
B.before
A.before
B.after
A.after
B.以前
A.以前
之后
之后
也就是说,延续是同步执行的
是否有办法在注册表通知中预测此顺序
我可以在注册表通知中保存SynchronizationContext.Current
并在以后调用tcs.TrySetResult
时进行比较。但这并不一定意味着等待tcs。任务将在我保存的上下文中执行
从理论上讲,如果我能预测到这一点,我也许可以用它来诊断和防止潜在的死锁。我认为没有一种文档化的方法可以预先预测SetResult
的同步/异步行为。如果您想显式地实施异步延续,则不信者@Damien_提出的Task.Run(()=>tcs.SetResult())
idea简单且通用
但是,如果您确实希望减少线程切换并仍然强制异步,则可以使用自定义dumbSynchronizationContext
包装tcs.SetResult
。它的唯一目的是与wait tcs.Task
的上下文(以及可能在tcs.Task
上注册的任何其他延续)相比,它的唯一性。这将导致TaskCompletionSource
的使用者端通过SynchronizationContext.Post
或池线程(如果使用者端没有同步上下文)进行异步继续
测试应用程序:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinForms_21845495
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.Load += async (s, e) =>
{
// test on WindowsFormsSynchronizationContext
await RequestNotificationAsync(notifyAsync: false);
Debug.WriteLine(String.Empty);
await RequestNotificationAsync(notifyAsync: true);
Debug.WriteLine(String.Empty);
// test on a pool thread
await Task.Run(() => RequestNotificationAsync(notifyAsync: false));
Debug.WriteLine(String.Empty);
await Task.Run(() => RequestNotificationAsync(notifyAsync: true));
Debug.WriteLine(String.Empty);
};
}
async Task RegisterNotification(TaskCompletionSource<object> tcs, bool notifyAsync)
{
await Task.Delay(500);
Debug.WriteLine("A.before");
if (notifyAsync)
{
tcs.SetResultAsync(null);
}
else
{
tcs.SetResult(null);
}
Debug.WriteLine("A.after");
}
async Task RequestNotificationAsync(bool notifyAsync)
{
var tcs = new TaskCompletionSource<object>();
var task = this.RegisterNotification(tcs, notifyAsync);
Debug.WriteLine("B.before");
var data = await tcs.Task;
// do not yeild
Thread.Sleep(500);
Debug.WriteLine("B.after");
// yeild
await Task.Delay(500);
}
}
public static class TaskExt
{
static public void SetResultAsync<T>(this TaskCompletionSource<T> tcs, T result)
{
FakeSynchronizationContext.Execute(() => tcs.SetResult(result));
}
// FakeSynchronizationContext
class FakeSynchronizationContext : SynchronizationContext
{
private static readonly ThreadLocal<FakeSynchronizationContext> s_context =
new ThreadLocal<FakeSynchronizationContext>(() => new FakeSynchronizationContext());
private FakeSynchronizationContext() { }
public static FakeSynchronizationContext Instance { get { return s_context.Value; } }
public static void Execute(Action action)
{
var savedContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(FakeSynchronizationContext.Instance);
try
{
action();
}
finally
{
SynchronizationContext.SetSynchronizationContext(savedContext);
}
}
// SynchronizationContext methods
public override SynchronizationContext CreateCopy()
{
return this;
}
public override void OperationStarted()
{
throw new NotImplementedException("OperationStarted");
}
public override void OperationCompleted()
{
throw new NotImplementedException("OperationCompleted");
}
public override void Post(SendOrPostCallback d, object state)
{
throw new NotImplementedException("Post");
}
public override void Send(SendOrPostCallback d, object state)
{
throw new NotImplementedException("Send");
}
}
}
}
使用系统;
使用系统诊断;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows.Forms;
名称空间WinForms_21845495
{
公共部分类主窗体:窗体
{
公共表格(
{
初始化组件();
this.Load+=async(s,e)=>
{
//WindowsFormsSynchronizationContext上的测试
Wait RequestNotificationAsync(notifyAsync:false);
Debug.WriteLine(String.Empty);
Wait RequestNotificationAsync(notifyAsync:true);
Debug.WriteLine(String.Empty);
//在池线程上进行测试
等待任务。运行(()=>RequestNotificationAsync(notifyAsync:false));
Debug.WriteLine(String.Empty);
等待任务。运行(()=>RequestNotificationAsync(notifyAsync:true));
Debug.WriteLine(String.Empty);
};
}
异步任务注册表通知(TaskCompletionSource tcs,bool notifyAsync)
{
等待任务。延迟(500);
Debug.WriteLine(“A.before”);
if(notifyAsync)
{
tcs.SetResultAsync(空);
}
其他的
{
tcs.SetResult(空);
}
Debug.WriteLine(“A.after”);
}
异步任务请求通知异步(bool notifyAsync)
{
var tcs=new TaskCompletionSource();
var task=this.RegisterNotification(tcs,notifyAsync);
Debug.WriteLine(“B.before”);
var data=等待tcs.Task;
//别笑
睡眠(500);
Debug.WriteLine(“B.after”);
//耶尔德
等待任务。延迟(500);
}
}
公共静态类TaskExt
{
静态公共void SetResultAsync(此TaskCompletionSource tcs,T结果)
{
FakeSynchronizationContext.Execute(()=>tcs.SetResult(result));
}
//伪造同步上下文
类FakeSynchronizationContext:SynchronizationContext
{
私有静态只读线程本地s_上下文=
new ThreadLocal(()=>new FakeSynchronizationContext());
私有FakeSynchronizationContext(){}
公共静态FakeSynchronizationContext实例{get{return s_context.Value;}}
公共静态无效执行(操作)
{
var savedContext=SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(FakeSynchronizationContext.Instance);
尝试
{
动作();
}
最后
{
SynchronizationContext.SetSynchronizationContext(savedContext);
}
}
//同步上下文方法
公共覆盖同步上下文CreateCopy()
{
归还这个;
}
公共覆盖无效操作开始()
{
抛出新的NotImplementedException(“OperationStarted”);
}
公共覆盖无效操作已完成()
{
抛出新的NotImplementedException(“操作已完成”);
}
公共重写void Post(sendorpostd,对象状态)
{
抛出新的NotImplementedException(“Post”);
}
公共覆盖无效发送(SendorPostD,对象状态)
{
抛出新的NotImplementedException(“发送”);
}
}
}
}
输出:
B.before
A.before
B.after
A.after
B.before
A.before
A.after
B.after
B.before
A.before
B.after
A.after
B.before
A.before
A.after
B.after
B.以前
A.以前
之后
之后
B.以前
A.以前
之后
之后
B.以前
A.以前
之后
之后
B.以前
A.以前
之后
之后
单个任务可以注册多个延续,并且每个延续可能具有不同的同步上下文。如果要确保它异步运行,请包装