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简单且通用

但是,如果您确实希望减少线程切换并仍然强制异步,则可以使用自定义dumb
SynchronizationContext
包装
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.以前 之后 之后
单个任务可以注册多个延续,并且每个延续可能具有不同的同步上下文。如果要确保它异步运行,请包装