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

附言:兄弟们,这个单例怎么样?
我回复:什么鬼,看不懂啊?!
也有其他小伙伴表示看不懂,看来大家的C#基础和我一样并不全面。
我看不懂,主要是因为我没用过TaskCompletionSource和Interlocked的CompareExchange方法,然后经过我1、2个小时的研究,终于勉强看懂了。
由于上面这段代码只贴了一张图,我没有拿到源码,所以我写了个差不多的Demo用于测试,代码如下:
  - using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace SingletonTest
- {
- public class Singleton
- {
- private static Task<string> _stringTask;
- /// <summary>
- /// 重置,方便重复测试
- /// </summary>
- public void Reset()
- {
- _stringTask = null;
- }
- public Task<string> InitAsync()
- {
- if (_stringTask != null)
- {
- return _stringTask;
- }
- var inition = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
- var initonTask = Interlocked.CompareExchange(ref _stringTask, inition.Task, null);
- if (initonTask != null)
- {
- return initonTask;
- }
- _stringTask = CreateContent(inition);
- return inition.Task;
- }
- private async Task<string> CreateContent(TaskCompletionSource<string> inition)
- {
- string content = await TextUtil.GetTextAsync();
- inition.SetResult(content);
- return content;
- }
- }
- }
复制代码 View Code然后按照我自己的习惯,又写了一版:
  - using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace SingletonTest
- {
- class Singleton2
- {
- private static string _value;
- private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
- /// <summary>
- /// 重置,方便重复测试
- /// </summary>
- public void Reset()
- {
- _value = null;
- }
- public async Task<string> InitAsync()
- {
- if (_value != null)
- {
- return _value;
- }
- await _semaphoreSlim.WaitAsync();
- if (_value == null)
- {
- _value = await TextUtil.GetTextAsync();
- }
- _semaphoreSlim.Release();
- return _value;
- }
- }
- }
复制代码 View Code很容易懂,不是吗?
这段代码我好像是理解了,可是我不理解的是,为什么代码会写的这么复杂呢?
最主要的是我不理解下面几行:
  - var inition = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
- var initonTask = Interlocked.CompareExchange(ref _stringTask, inition.Task, null);
- if (initonTask != null)
- {
- return initonTask;
- }
复制代码 View Code我要给它翻译成我能理解的代码,我意思到new的TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously)也是个单例,所以我先写了个TaskCompletionSourceFactory类:
  - using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace SingletonTest
- {
- public class TaskCompletionSourceFactory : IDisposable
- {
- private TaskCompletionSource<string> _value;
- private TaskCompletionSourceData _data;
- private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
- public TaskCompletionSourceData Instance
- {
- get
- {
- _semaphoreSlim.Wait();
- if (_value == null)
- {
- _data = new TaskCompletionSourceData();
- _value = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
- _data.Value = _value;
- _data.First = true;
- }
- else
- {
- _data = new TaskCompletionSourceData();
- _data.Value = _value;
- _data.First = false;
- }
- _semaphoreSlim.Release();
- return _data;
- }
- }
- public void Dispose()
- {
- _semaphoreSlim.Dispose();
- }
- }
- public class TaskCompletionSourceData
- {
- public bool First { get; set; }
- public TaskCompletionSource<string> Value { get; set; }
- }
- }
复制代码 View Code然后把Demo中Singleton这个类改写了一下:
  - using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace SingletonTest
- {
- public class Singleton3
- {
- private static Task<string> _stringTask;
- /// <summary>
- /// 重置,方便重复测试
- /// </summary>
- public void Reset()
- {
- _stringTask = null;
- }
- public Task<string> InitAsync(TaskCompletionSourceFactory factory)
- {
- if (_stringTask != null)
- {
- return _stringTask;
- }
- var inition = factory.Instance;
- if (!inition.First)
- {
- return inition.Value.Task;
- }
- _stringTask = CreateContent(inition.Value);
- return inition.Value.Task;
- }
- private async Task<string> CreateContent(TaskCompletionSource<string> inition)
- {
- string content = await TextUtil.GetTextAsync();
- inition.SetResult(content);
- return content;
- }
- }
- }
复制代码 View Code当我差不多理解了之后,我发现原始代码有一点点小问题,就是TaskCompletionSource是有机率被重复new的。
大家觉得哪种写法好呢?
附:
TextUtil.cs代码,是一个模拟获取文本的方法:
  - using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace SingletonTest
- {
- public class TextUtil
- {
- public static Task<string> GetTextAsync()
- {
- return Task.Run<string>(() =>
- {
- Thread.Sleep(10);
- Random rnd = new Random();
- return rnd.Next(0, 1000).ToString().PadRight(10);
- });
- }
- }
- }
复制代码 View Code测试代码:
 View Code
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |