颐和api

TaskHelper.cs 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Runtime.CompilerServices;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace MadRunFabric.Common
  10. {
  11. /// <summary>
  12. /// 同步调用异步async防止死锁方案
  13. ///
  14. /// 当前代码地址
  15. /// https://github.com/tejacques/AsyncBridge/blob/master/src/AsyncBridge/AsyncHelper.cs
  16. ///
  17. /// https://github.com/tejacques/AsyncBridge
  18. /// http://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously
  19. /// https://social.msdn.microsoft.com/Forums/en-US/163ef755-ff7b-4ea5-b226-bbe8ef5f4796/is-there-a-pattern-for-calling-an-async-method-synchronously?forum=async
  20. /// </summary>
  21. public static class AsyncHelper
  22. {
  23. /// <summary>
  24. /// Execute's an async Task<T> method which has a void return value synchronously
  25. /// </summary>
  26. /// <param name="task">Task<T> method to execute</param>
  27. public static void RunSync(Func<Task> task)
  28. {
  29. var oldContext = SynchronizationContext.Current;
  30. var synch = new ExclusiveSynchronizationContext();
  31. SynchronizationContext.SetSynchronizationContext(synch);
  32. synch.Post(async _ =>
  33. {
  34. try
  35. {
  36. await task();
  37. }
  38. catch (Exception e)
  39. {
  40. synch.InnerException = e;
  41. throw;
  42. }
  43. finally
  44. {
  45. synch.EndMessageLoop();
  46. }
  47. }, null);
  48. synch.BeginMessageLoop();
  49. SynchronizationContext.SetSynchronizationContext(oldContext);
  50. }
  51. /// <summary>
  52. /// Execute's an async Task<T> method which has a T return type synchronously
  53. /// </summary>
  54. /// <typeparam name="T">Return Type</typeparam>
  55. /// <param name="task">Task<T> method to execute</param>
  56. /// <returns></returns>
  57. public static T RunSync<T>(Func<Task<T>> task)
  58. {
  59. var oldContext = SynchronizationContext.Current;
  60. var synch = new ExclusiveSynchronizationContext();
  61. SynchronizationContext.SetSynchronizationContext(synch);
  62. T ret = default(T);
  63. synch.Post(async _ =>
  64. {
  65. try
  66. {
  67. ret = await task();
  68. }
  69. catch (Exception e)
  70. {
  71. synch.InnerException = e;
  72. throw;
  73. }
  74. finally
  75. {
  76. synch.EndMessageLoop();
  77. }
  78. }, null);
  79. synch.BeginMessageLoop();
  80. SynchronizationContext.SetSynchronizationContext(oldContext);
  81. return ret;
  82. }
  83. private class ExclusiveSynchronizationContext : SynchronizationContext
  84. {
  85. private bool done;
  86. public Exception InnerException { get; set; }
  87. readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
  88. readonly Queue<Tuple<SendOrPostCallback, object>> items =
  89. new Queue<Tuple<SendOrPostCallback, object>>();
  90. public override void Send(SendOrPostCallback d, object state)
  91. {
  92. throw new NotSupportedException("We cannot send to our same thread");
  93. }
  94. public override void Post(SendOrPostCallback d, object state)
  95. {
  96. lock (items)
  97. {
  98. items.Enqueue(Tuple.Create(d, state));
  99. }
  100. workItemsWaiting.Set();
  101. }
  102. public void EndMessageLoop()
  103. {
  104. Post(_ => done = true, null);
  105. }
  106. public void BeginMessageLoop()
  107. {
  108. while (!done)
  109. {
  110. Tuple<SendOrPostCallback, object> task = null;
  111. lock (items)
  112. {
  113. if (items.Count > 0)
  114. {
  115. task = items.Dequeue();
  116. }
  117. }
  118. if (task != null)
  119. {
  120. task.Item1(task.Item2);
  121. if (InnerException != null) // the method threw an exeption
  122. {
  123. throw new AggregateException($"AsyncHelpers.Run Exception.{InnerException.Message}", InnerException);
  124. }
  125. }
  126. else
  127. {
  128. workItemsWaiting.WaitOne();
  129. }
  130. }
  131. }
  132. public override SynchronizationContext CreateCopy()
  133. {
  134. return this;
  135. }
  136. }
  137. }
  138. /// <summary>
  139. /// Class AsyncHelper.
  140. /// </summary>
  141. public static class AsyncHelper_
  142. {
  143. private static readonly TaskFactory MyTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
  144. /// <summary>在同步方法中不死锁方式调用异步方法</summary>
  145. public static TResult RunSync<TResult>(Func<Task<TResult>> func)
  146. {
  147. var currentUiCulture = CultureInfo.CurrentUICulture;
  148. var currentCulture = CultureInfo.CurrentCulture;
  149. return MyTaskFactory.StartNew(() =>
  150. {
  151. Thread.CurrentThread.CurrentCulture = currentCulture;
  152. Thread.CurrentThread.CurrentUICulture = currentUiCulture;
  153. return func();
  154. })
  155. .Unwrap()
  156. .GetAwaiter()
  157. .GetResult();
  158. }
  159. /// <summary>在同步方法中不死锁方式调用异步方法</summary>
  160. public static void RunSync(Func<Task> func)
  161. {
  162. var currentUiCulture = CultureInfo.CurrentUICulture;
  163. var currentCulture = CultureInfo.CurrentCulture;
  164. MyTaskFactory.StartNew(() =>
  165. {
  166. Thread.CurrentThread.CurrentCulture = currentCulture;
  167. Thread.CurrentThread.CurrentUICulture = currentUiCulture;
  168. return func();
  169. })
  170. .Unwrap()
  171. .GetAwaiter()
  172. .GetResult();
  173. }
  174. }
  175. }