C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决
关于死锁的原因
理解该死锁的原因在于理解await 处理contexts的方式,默认的,当一个未完成的Task 被await的时候,当前的上下文将在该Task完成的时候重新获得并继续执行剩余的代码。这个context就是当前的SynchronizationContext ,除非它是空的。WEB应用程序的SynchronizationContext 有排他性,只允许一个线程运行。当await 完成的时候,它试图在它原来的代码上下文执行它剩余的部分,但是该代码上下文中已经有一个线程在了,就是那个一直在同步等待async 完成的那个线程,它们两个相互等待,因此就死锁了。
MSDN使用异步应该注意
规则 |
描述 |
例外 |
避免使用 async void |
优先使用 async Task 而不用 async void |
Event handlers |
Async到顶 |
不要混合使用 blocking 和 async 的代码 |
Console main method |
注意配置好执行的context |
尽量设置 ConfigureAwait(false) |
需要context的除外 |
感恩的心
多谢网上很多文章的分享,在相关文章中找到了在同步代码中使用异步代码的无阻塞方案,之前也自己写了几个测试的DEMO,但Task<T>这种带有返回值的异步方法还是会出现死锁,之前代码如下:
/// <summary>
/// 大叔测试
/// </summary>
public class tools
{
#region 假设这些方法被第三方被封装的,不可修改的方法
public static async Task TestAsync()
{
await Task.Delay()
.ConfigureAwait(false);//不会死锁
} public static async Task<string> GetStrAsync()
{
return await Task.Run(() => "OK").ConfigureAwait(false);
} public static async Task DelayTestAsync()
{
Logger.LoggerFactory.Instance.Logger_Info("DelayAsync");
await Task.Delay();
} public static async Task<string> DelayGetStrAsync()
{
return await Task.Run(() => "OK");
}
#endregion #region 我们需要在自己代码中封装它,解决线程死锁
/// <summary>
/// 没有返回值的同步调用异步的实体
/// </summary>
/// <param name="func"></param>
public static void ForWait(Func<Task> func)
{
func().ConfigureAwait(false);
}
/// <summary>
/// 存在返回值的同步调用异步的实体
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public static T ForResult<T>(Func<Task<T>> func)
{
var a = func();
a.ConfigureAwait(false);
return a.Result;
}
#endregion
}
对于上面的代码,当执行一个Task反回类型(即无返回结果)时,程序是没有问题的,但可以存在返回结果,那么上面的ForResult方法依旧会产生死锁!执着的我当然不会就此罢休,找了一些文章后,终于还是有了结果,在对当前上下文和异步上下文进行了简
单的处理后,最终还是实现了同步与异步的并存,所以说,人是最聪明的一种动物,一切都皆有可能,只要你想!
Lind.DDD.Utils.AsyncTaskManager代码如下,希望可以给大家带来一些启发和帮助
/// <summary>
/// 异步线程管理-在同步程序中调用异步,解决了线程死锁问题
/// </summary>
public class AsyncTaskManager
{
/// <summary>
/// 运行无返回类型的异步方法
/// </summary>
/// <param name="task"></param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;//同步上下文
var synch = new ExclusiveSynchronizationContext();//异步上下文
SynchronizationContext.SetSynchronizationContext(synch);//设置当前同步上下文
synch.Post(async obj =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// 运行返回类型为T的异步方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default(T);//动作的默认值
synch.Post(async obj =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
} /// <summary>
/// 异步上下文对象
/// </summary>
class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
new Queue<Tuple<SendOrPostCallback, object>>(); public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
/// <summary>
/// 添加到异步队列
/// </summary>
/// <param name="d"></param>
/// <param name="state"></param>
public override void Post(SendOrPostCallback d, object state)
{
lock (items)
{
items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
}
/// <summary>
/// 异步结束
/// </summary>
public void EndMessageLoop()
{
Post(obj => done = true, null);
}
/// <summary>
/// 处理异步队列中的消息
/// </summary>
public void BeginMessageLoop()
{
while (!done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
{
if (items.Count > )
{
task = items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncInline.Run method threw an exception.",
InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
}
最后我们进行测试中,看到线程没有出现死锁问题!
感谢各位的阅读!
C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决的更多相关文章
- C#~异步编程再续~await与async引起的w3wp.exe崩溃
返回目录 最近怪事又开始发生了,IIS的应用程序池无做挂掉,都指向同一个矛头,async,threadPool,Task,还有一个System.NullReferenceException,所以这些都 ...
- C#中的异步编程--探索await与async关键字的奥妙之处,原来理解和使用异步编程可以这么简单
前言 await与async是C#5.0推出的新语法,关于await与async有很多文章讲解.但看完后有没有这样一种感觉,感觉这东西像是不错,但好像就是看不太懂,也不清楚该怎么使用.虽然偶有接触,但 ...
- 异步编程,await async入门
网上很多异步编程的文章,提供一篇入门: 异步编程模型 .net支持3种异步编程模式: msdn:https://docs.microsoft.com/zh-cn/dotnet/standard/asy ...
- C#进阶——从应用上理解异步编程的作用(async / await)
欢迎来到学习摆脱又加深内卷篇 下面是学习异步编程的应用 1.首先,我们建一个winfrom的项目,界面如下: 2.然后先写一个耗时函数: /// <summary> /// 耗时工作 // ...
- 【C# TAP 异步编程】三、async\await的运作机理详解
[原创] 本文只是个人笔记,很多错误,欢迎指出. 环境:vs2022 .net6.0 C#10 参考:https://blog.csdn.net/brook_shi/article/details/ ...
- js异步编程终级解决方案 async/await
在最新的ES7(ES2017)中提出的前端异步特性:async.await. async.await是什么 async顾名思义是“异步”的意思,async用于声明一个函数是异步的.而await从字 ...
- JavaScript异步编程:Generator与Async
从Promise开始,JavaScript就在引入新功能,来帮助更简单的方法来处理异步编程,帮助我们远离回调地狱. Promise是下边要讲的Generator/yield与async/await的基 ...
- C#~异步编程再续~你必须要知道的ThreadPool里的throw
问题依旧存在 之前写过相关文章异步编程的文章,本文主要还是一点补充,之前在IIS经常发w3wp进程无做挂了的情况,但一直没能找到真正的原因,而查找相关资料,找了一些相关的文章,如await和async ...
- C#~异步编程再续~async异步方法与同步方法的并行
返回目录 今天晚上没事写了个测试的代码,又看了看.net的并行编程,两个方法,一个是异步async修饰的,另一个是普通的方法,在控制台程序的Main方法里去调用这两个方法,会有什么结果呢? 首先我们看 ...
随机推荐
- Java中的多态
1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal {public abstract void Say();} 子类: public class ...
- pdo的使用
PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口. PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据. PDO随 ...
- 我这么玩Web Api(一):帮助页面或用户手册(Microsoft and Swashbuckle Help Page)
前言 你需要为客户编写Api调用手册?你需要测试你的Api接口?你需要和前端进行接口对接?那么这篇文章应该可以帮到你.本文将介绍创建Web Api 帮助文档页面的两种方式,Microsoft Help ...
- AbpZero--2.如何启动
1.直接启动 VS中直接启动 2.IIS站点 IIS中配置一个站点来启动(推荐) 3.登录 系统默认创建2个用户 默认用户名:admin 密码:123qwe 租户:Default 默认用户名:adm ...
- TCP/IP之TCP_NODELAY与TCP_CORK
TCP/IP之Nagle算法与40ms延迟提到了Nagle 算法.这样虽然提高了网络吞吐量,但是实时性却降低了,在一些交互性很强的应用程序来说是不允许的,使用TCP_NODELAY选项可以禁止Nagl ...
- JavaScript中的this
本文尽量避免概念性的讲解,那样太抽象 所以下面以一些简单的例子,从易到难对this的用法总结 1.方法中的this会指向当前执行该方法的对象 如: var name = "window&qu ...
- [斜率优化DP]【学习笔记】【更新中】
参考资料: 1.元旦集训的课件已经很好了 http://files.cnblogs.com/files/candy99/dp.pdf 2.http://www.cnblogs.com/MashiroS ...
- 杂项之python描述符协议
杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...
- 我的MYSQL学习心得(八) 插入 更新 删除
我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...
- ASP.NET跨平台最佳实践
前言 八年的坚持敌不过领导的固执,最终还是不得不阔别已经成为我第二语言的C#,转战Java阵营.有过短暂的失落和迷茫,但技术转型真的没有想象中那么难.回头审视,其实单从语言本身来看,C#确实比Java ...