为什么有的人把代码写的如此复杂?

种地  金牌会员 | 2022-8-31 04:42:45 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 942|帖子 942|积分 2826

技术群里有人发了一段代码:

附言:兄弟们,这个单例怎么样?
我回复:什么鬼,看不懂啊?!
也有其他小伙伴表示看不懂,看来大家的C#基础和我一样并不全面。
我看不懂,主要是因为我没用过TaskCompletionSource和Interlocked的CompareExchange方法,然后经过我1、2个小时的研究,终于勉强看懂了。
由于上面这段代码只贴了一张图,我没有拿到源码,所以我写了个差不多的Demo用于测试,代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace SingletonTest
  8. {
  9.     public class Singleton
  10.     {
  11.         private static Task<string> _stringTask;
  12.         /// <summary>
  13.         /// 重置,方便重复测试
  14.         /// </summary>
  15.         public void Reset()
  16.         {
  17.             _stringTask = null;
  18.         }
  19.         public Task<string> InitAsync()
  20.         {
  21.             if (_stringTask != null)
  22.             {
  23.                 return _stringTask;
  24.             }
  25.             var inition = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
  26.             var initonTask = Interlocked.CompareExchange(ref _stringTask, inition.Task, null);
  27.             if (initonTask != null)
  28.             {
  29.                 return initonTask;
  30.             }
  31.             _stringTask = CreateContent(inition);
  32.             return inition.Task;
  33.         }
  34.         private async Task<string> CreateContent(TaskCompletionSource<string> inition)
  35.         {
  36.             string content = await TextUtil.GetTextAsync();
  37.             inition.SetResult(content);
  38.             return content;
  39.         }
  40.     }
  41. }
复制代码
View Code然后按照我自己的习惯,又写了一版:
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace SingletonTest
  9. {
  10.     class Singleton2
  11.     {
  12.         private static string _value;
  13.         private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
  14.         /// <summary>
  15.         /// 重置,方便重复测试
  16.         /// </summary>
  17.         public void Reset()
  18.         {
  19.             _value = null;
  20.         }
  21.         public async Task<string> InitAsync()
  22.         {
  23.             if (_value != null)
  24.             {
  25.                 return _value;
  26.             }
  27.             await _semaphoreSlim.WaitAsync();
  28.             if (_value == null)
  29.             {
  30.                 _value = await TextUtil.GetTextAsync();
  31.             }
  32.             _semaphoreSlim.Release();
  33.             return _value;
  34.         }
  35.     }
  36. }
复制代码
View Code很容易懂,不是吗? 
这段代码我好像是理解了,可是我不理解的是,为什么代码会写的这么复杂呢?
最主要的是我不理解下面几行:
  1. var inition = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
  2. var initonTask = Interlocked.CompareExchange(ref _stringTask, inition.Task, null);
  3. if (initonTask != null)
  4. {
  5.     return initonTask;
  6. }
复制代码
View Code我要给它翻译成我能理解的代码,我意思到new的TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously)也是个单例,所以我先写了个TaskCompletionSourceFactory类:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace SingletonTest
  8. {
  9.     public class TaskCompletionSourceFactory : IDisposable
  10.     {
  11.         private TaskCompletionSource<string> _value;
  12.         private TaskCompletionSourceData _data;
  13.         private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
  14.         public TaskCompletionSourceData Instance
  15.         {
  16.             get
  17.             {
  18.                 _semaphoreSlim.Wait();
  19.                 if (_value == null)
  20.                 {
  21.                     _data = new TaskCompletionSourceData();
  22.                     _value = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
  23.                     _data.Value = _value;
  24.                     _data.First = true;
  25.                 }
  26.                 else
  27.                 {
  28.                     _data = new TaskCompletionSourceData();
  29.                     _data.Value = _value;
  30.                     _data.First = false;
  31.                 }
  32.                 _semaphoreSlim.Release();
  33.                 return _data;
  34.             }
  35.         }
  36.         public void Dispose()
  37.         {
  38.             _semaphoreSlim.Dispose();
  39.         }
  40.     }
  41.     public class TaskCompletionSourceData
  42.     {
  43.         public bool First { get; set; }
  44.         public TaskCompletionSource<string> Value { get; set; }
  45.     }
  46. }
复制代码
View Code然后把Demo中Singleton这个类改写了一下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace SingletonTest
  8. {
  9.     public class Singleton3
  10.     {
  11.         private static Task<string> _stringTask;
  12.         /// <summary>
  13.         /// 重置,方便重复测试
  14.         /// </summary>
  15.         public void Reset()
  16.         {
  17.             _stringTask = null;
  18.         }
  19.         public Task<string> InitAsync(TaskCompletionSourceFactory factory)
  20.         {
  21.             if (_stringTask != null)
  22.             {
  23.                 return _stringTask;
  24.             }
  25.             var inition = factory.Instance;
  26.             if (!inition.First)
  27.             {
  28.                 return inition.Value.Task;
  29.             }
  30.             _stringTask = CreateContent(inition.Value);
  31.             return inition.Value.Task;
  32.         }
  33.         private async Task<string> CreateContent(TaskCompletionSource<string> inition)
  34.         {
  35.             string content = await TextUtil.GetTextAsync();
  36.             inition.SetResult(content);
  37.             return content;
  38.         }
  39.     }
  40. }
复制代码
View Code当我差不多理解了之后,我发现原始代码有一点点小问题,就是TaskCompletionSource是有机率被重复new的。
大家觉得哪种写法好呢?
附:
TextUtil.cs代码,是一个模拟获取文本的方法:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace SingletonTest
  8. {
  9.     public class TextUtil
  10.     {
  11.         public static Task<string> GetTextAsync()
  12.         {
  13.             return Task.Run<string>(() =>
  14.             {
  15.                 Thread.Sleep(10);
  16.                 Random rnd = new Random();
  17.                 return rnd.Next(0, 1000).ToString().PadRight(10);
  18.             });
  19.         }
  20.     }
  21. }
复制代码
View Code测试代码:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace SingletonTest
  8. {
  9.     class Program
  10.     {
  11.         private static int _count = 200;
  12.         private static Singleton _singleton = new Singleton();
  13.         private static Singleton2 _singleton2 = new Singleton2();
  14.         private static Singleton3 _singleton3 = new Singleton3();
  15.         static void Main(string[] args)
  16.         {
  17.             ThreadPool.SetMinThreads(20, 20);
  18.             Task.Run(() => { }); //Task预热
  19.             Console.WriteLine("输入1测试Singleton,输入2测试Singleton2,如果值都相同,说明单例测试通过,否则不通过");
  20.             while (true)
  21.             {
  22.                 var key = Console.ReadKey().Key;
  23.                 if (key == ConsoleKey.D1)
  24.                 {
  25.                     Console.WriteLine("测试Singleton");
  26.                     Test();
  27.                 }
  28.                 if (key == ConsoleKey.D2)
  29.                 {
  30.                     Console.WriteLine("测试Singleton2");
  31.                     Test2();
  32.                 }
  33.                 if (key == ConsoleKey.D3)
  34.                 {
  35.                     Console.WriteLine("测试Singleton3");
  36.                     Test3();
  37.                 }
  38.             }
  39.         }
  40.         public static void Test()
  41.         {
  42.             List<Task> taskList = new List<Task>();
  43.             for (int i = 0; i < _count; i++)
  44.             {
  45.                 Task task = Task.Run(async () =>
  46.                 {
  47.                     string content = await _singleton.InitAsync();
  48.                     Console.Write(content);
  49.                 });
  50.                 taskList.Add(task);
  51.             }
  52.             Task.WaitAll(taskList.ToArray());
  53.             _singleton.Reset();
  54.             Console.WriteLine("");
  55.         }
  56.         public static void Test2()
  57.         {
  58.             List<Task> taskList = new List<Task>();
  59.             for (int i = 0; i < _count; i++)
  60.             {
  61.                 Task task = Task.Run(async () =>
  62.                 {
  63.                     string content = await _singleton2.InitAsync();
  64.                     Console.Write(content);
  65.                 });
  66.                 taskList.Add(task);
  67.             }
  68.             Task.WaitAll(taskList.ToArray());
  69.             _singleton2.Reset();
  70.             Console.WriteLine("");
  71.         }
  72.         public static void Test3()
  73.         {
  74.             TaskCompletionSourceFactory factory = new TaskCompletionSourceFactory();
  75.             List<Task> taskList = new List<Task>();
  76.             for (int i = 0; i < _count; i++)
  77.             {
  78.                 Task task = Task.Run(async () =>
  79.                 {
  80.                     string content = await _singleton3.InitAsync(factory);
  81.                     Console.Write(content);
  82.                 });
  83.                 taskList.Add(task);
  84.             }
  85.             Task.WaitAll(taskList.ToArray());
  86.             _singleton3.Reset();
  87.             factory.Dispose();
  88.             Console.WriteLine("");
  89.         }
  90.     }
  91. }
复制代码
View Code 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

种地

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表