.net异步Task转同步


推荐方法

C# 全选
    /// <summary>
    /// 异步转同步,防止ASP.NET中死锁
    /// https://cpratt.co/async-tips-tricks/
    /// </summary>
    public static class AsyncHelper
    {
        private static readonly TaskFactory _myTaskFactory =
            new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

        /// <summary>
        /// 同步执行
        /// </summary>
        /// <param name="func">任务</param>
        public static void RunSync(Func<Task> func)
        {
            _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }

        /// <summary>
        /// 同步执行
        /// </summary>
        /// <typeparam name="TResult">返回类型</typeparam>
        /// <param name="func">任务</param>
        /// <returns></returns>
        public static TResult RunSync<TResult>(Func<Task<TResult>> func)
        {
            return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
        }
    }

历史记录

使用 Task.GetAwaiter().GetResult();可转换为同步

C# 全选
RestResponse response = client.ExecuteAsync(request).GetAwaiter().GetResult();

 

延申资料

前几天在用线程池执行一些任务时运到一种情形,就是回调方法中使用到了异步方法,但是回调方法貌似不支持async await的写法。这时候我应该如何处理呢?是使用Task.Result来获取返回结果,还是使用GetAwaiter.GetResult()呢?本文就来探讨下吧。

这里先上我这种场景的伪代码:

C# 全选
ThreadPool.QueueUserWorkItem(ExcuteScanProcess, node);

ExcuteScanProcess这个回调方法中

C# 全选
private void ExcuteScanProcess(object state)
{
    ……其他处理……
    repository.UpdateAsync(node).ConfigureAwait(false).GetAwaiter().GetResult();
    ……其他处理……
}

如上图所示repository.UpdateAsync(node)属于一部方法,这时候我想要等待它异步执行完成之后再执行后续的逻辑。这时候我有两种选择,是直接

C# 全选
repository.UpdateAsync(node).ConfigureAwait(false).GetAwaiter().GetResult();

好呢,还是

C# 全选
repository.UpdateAsync(node).ConfigureAwait(false).Result;

好呢?

为此我查找了相关的资料,对它俩的区别做一个简单的总结:

其实这两个使用方式是差不多的。不过,还是有一点小小的区别的:如果任务失败,Task.GetAwaiter().GetResult()会直接抛出异常,而Task.Result则会把异常包装在AggregateException中。从这个角度说Task.GetAwaiter().GetResult()要优于Task.Result。毕竟它少了异常的包装操作,即直接抛出异常,而不是把异常包装在AggregateException中。

下面的引言解释了为什么Task.Result不仅仅包含Task.GetAwaiter().GetResult()(由于“非常高的兼容性”)的异常传播行为。

如前所述,我们有一个非常高的兼容性标准,因此我们避免了改动。因此,Task.Wait保留了始终包装的原始行为。但是,您可能会发现自己处在某些高级情况下,这些情况下您想要的行为类似于所采用的同步阻塞Task.Wait,但是您希望将原始异常展开而不是传播,而不是将其封装在AggregateException中。为此,您可以直接定位任务的等待者。当您编写“ await task;”时,编译器Task.GetAwaiter()会将其转换为方法的用法,这将返回具有GetResult()方法的实例。当用于有故障的任务时,GetResult()将传播原始异常(这是“ await task;” 如何获得其行为)。因此,您可以使用“task.GetAwaiter().GetResult()如果您想直接调用此传播逻辑。

https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

GetResult”实际上表示“检查任务是否有错误” 通常,我会尽力避免对异步任务进行同步阻塞。但是,在少数情况下,我确实违反了该准则。在那些罕见的情况下,我的首选方法是GetAwaiter().GetResult()因为它保留任务异常,而不是将它们包装在中AggregateException

总结

通过上述内容的阐述,因此在那些必须对异步任务进行同步阻塞的场景中,我选择使用GetAwaiter().GetResult()

 

参考资料:

https://cloud.tencent.com/developer/article/1649197

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
张国生
上一篇:Devexpress使用自带的图标库图标
下一篇:Devexpress TreeList等一段时间展开就会很卡
评论列表

发表评论

评论内容
昵称:
关联文章

.net异步Task同步
Task 使用详细[基础操作,异步原则,异步函数,异步模式]
C# 从做早餐看同步异步
Javascript 中通过 yield 和 promise 使异步同步
.NET使用TaskCompletionSource将事件转移到异步方法
vue中异步函数async和await的用法
EFCore异步查询报错
软件:批量HEICJPG 苹果手机照片格式JPG
.net 简单实现在H5中将word、jpg、png成PDF给PDF添加水印并且控制样式和可视化编辑
化繁为简,用几个例子介绍JavaScript异步处理async awite
Devexpress 表格GridView列RepositoryItemPictureEdit异步加载远程URL图片
RSA PrivateKey私钥字符串PEM格式证书
C#汉字拼音
EF异步查询ToListAsync报错
C# 十六进制字符串byte[],Byte[] String
Python对象json字符串
vscode同步配置时,重新生成 github token 之后,怎样继续下载配置
对象和Datatable互
C# PNGICO,ICOPNG,PNG图标常规尺寸互
C#代码:byte[] 十六进制字符串

联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码