翼度科技»论坛 编程开发 .net 查看内容

ET介绍——C#更好的协程

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
更好的协程

上文讲了一串回调就是协程,显然这样写代码,增加逻辑,插入逻辑非常容易出错。我们需要利用异步语法把这个异步回调的形式改成同步的形式,幸好C#已经帮我们设计好了,看代码
  1. // example2_2
  2.     class Program
  3.     {
  4.         private static int loopCount = 0;
  5.         
  6.         static void Main(string[] args)
  7.         {
  8.             OneThreadSynchronizationContext _ = OneThreadSynchronizationContext.Instance;
  9.             Console.WriteLine($"主线程: {Thread.CurrentThread.ManagedThreadId}");
  10.             
  11.             Crontine();
  12.             
  13.             while (true)
  14.             {
  15.                 OneThreadSynchronizationContext.Instance.Update();
  16.                
  17.                 Thread.Sleep(1);
  18.                
  19.                 ++loopCount;
  20.                 if (loopCount % 10000 == 0)
  21.                 {
  22.                     Console.WriteLine($"loop count: {loopCount}");
  23.                 }
  24.             }
  25.         }
  26.         private static async void Crontine()
  27.         {
  28.             await WaitTimeAsync(5000);
  29.             Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
  30.             await WaitTimeAsync(4000);
  31.             Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
  32.             await WaitTimeAsync(3000);
  33.             Console.WriteLine($"当前线程: {Thread.CurrentThread.ManagedThreadId}, WaitTimeAsync finsih loopCount的值是: {loopCount}");
  34.         }
  35.         
  36.         private static Task WaitTimeAsync(int waitTime)
  37.         {
  38.             TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
  39.             Thread thread = new Thread(()=>WaitTime(waitTime, tcs));
  40.             thread.Start();
  41.             return tcs.Task;
  42.         }
  43.         
  44.         /// <summary>
  45.         /// 在另外的线程等待
  46.         /// </summary>
  47.         private static void WaitTime(int waitTime, TaskCompletionSource<bool> tcs)
  48.         {
  49.             Thread.Sleep(waitTime);
  50.             
  51.             // 将tcs扔回主线程执行
  52.             OneThreadSynchronizationContext.Instance.Post(o=>tcs.SetResult(true), null);
  53.         }
  54.     }
复制代码
 
在这段代码里面,WaitTimeAsync方法中,我们利用了TaskCompletionSource类替代了之前传入的Action参数,WaitTimeAsync方法返回了一个Task类型的结果。WaitTime中我们把action()替换成了tcs.SetResult(true),WaitTimeAsync方法前使用await关键字,这样可以将一连串的回调改成同步的形式。这样一来代码显得十分简洁,开发起来也方便多了。
这里还有个技巧,我们发现WaitTime中需要将tcs.SetResult扔回到主线程执行,微软给我们提供了一种简单的方法,参考example2_2_2,在主线程设置好同步上下文,
  1. // example2_2_2
  2. SynchronizationContext.SetSynchronizationContext(OneThreadSynchronizationContext.Instance);
复制代码
 
在WaitTime中直接调用tcs.SetResult(true)就行了,回调会自动扔到同步上下文中,而同步上下文我们可以在主线程中取出回调执行,这样自动能够完成回到主线程的操作
  1.         private static void WaitTime(int waitTime, TaskCompletionSource<bool> tcs)
  2.         {
  3.             Thread.Sleep(waitTime);
  4.             tcs.SetResult(true);
  5.         }
复制代码
 
如果不设置同步上下文,你会发现打印出来当前线程就不是主线程了,这也是很多第三方库跟.net core内置库的用法,默认不回调到主线程,所以我们使用的时候需要设置下同步上下文。其实这个设计本人觉得没有必要,交由库的开发者去实现更好,尤其是在游戏开发中,逻辑全部是单线程的,回调每次都走一遍同步上下文就显得多余了,所以ET框架提供了不使用同步上下文的实现ETTask,代码更加简洁更加高效,这个后面会讲到。
ET开源地址地址:egametang/ET: Unity3D Client And C# Server Framework (github.com)   qq群:474643097

来源:https://www.cnblogs.com/flamesky/archive/2023/05/18/17413672.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具