欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > C# >内容正文

C#

C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决

发布时间:2024/4/14 C# 68 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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(1000).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(1000);}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 > 0){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;}}}

最后我们进行测试中,看到线程没有出现死锁问题!

感谢各位的阅读!

返回目录

转载于:https://www.cnblogs.com/lori/p/5481820.html

总结

以上是生活随笔为你收集整理的C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。