首页
视频
资源
登录
原
.net core Task的学习理解(下)
5831
人阅读
2021/8/20 13:31
总访问:
2536554
评论:
0
收藏:
0
手机
分类:
.net后台框架
![.netcore](https://img.tnblog.net/arcimg/hb/c857299a86d84ee7b26d181a31e58234.jpg ".netcore") >#.net core Task的学习理解(下) [TOC] Task.GetResult与死锁 ------------ tn2>通过下面的代码,可能会造成死锁的情况。 ```csharp static async Task Main(string[] args) { Console.WriteLine("Test:Start"); DoSthAsync().GetAwaiter().GetResult(); Console.WriteLine("Test:END"); Console.ReadLine(); } static async Task DoSthAsync() { Console.WriteLine("DoSthAsync: START"); await Task.Delay(100); Console.WriteLine("DoSthAsync: END"); } ``` tn2>但是通过如下代码就可以完成运行。这将与同步上下文有关,也就是`SynchronizationContext`类 ```csharp static async Task Main(string[] args) { Console.WriteLine("Test:Start"); DoSthAsync().GetAwaiter().GetResult(); Console.WriteLine("Test:END"); Console.ReadLine(); } static async Task DoSthAsync() { Console.WriteLine("DoSthAsync: START"); await Task.Delay(100).ConfigureAwait(continueOnCapturedContext:false); Console.WriteLine("DoSthAsync: END"); } ``` ![](https://img.tnblog.net/arcimg/hb/09ca28d7cca545a2b83db5b69d36dda0.png) SynchronizationContext与Task回调处理 ------------ tn2>Task不仅可以让TaskScheduler调用,还可以使用SynchronizationContext。 TaskAwaiter在实际注册回调的时候会对回调进行包装,决定了回调会在哪里执行。 当SynchronizationContext.Current不为为null时将会到SynchronizationContext上执行回调,为空是才会去判断TaskScheduler。(具体示意图如下) ![](https://img.tnblog.net/arcimg/hb/2998e1f06a274e869df7e8edd962987f.png) >### 自定义SynchronizationContext ```csharp class MaxConcurrencySynchronizationContext: SynchronizationContext { /// <summary> /// 创建一个信号量 /// </summary> private readonly SemaphoreSlim _semaphore; public MaxConcurrencySynchronizationContext(int maxConcurrencyLevel) => _semaphore = new SemaphoreSlim(maxConcurrencyLevel); public override void Post(SendOrPostCallback d, object state) { _semaphore.Wait(); try { Console.WriteLine("MaxConcurrencySynchronizationContext.ThreadId:{0}",Thread.CurrentThread.ManagedThreadId); d(state); } finally { _semaphore.Release(); } } public override void Send(SendOrPostCallback d, object state) => throw new NotImplementedException(); } ``` tn2>添加测试代码 ```csharp static void Main(string[] args) { Task.Run(() => { var mcs = new MaxConcurrencySynchronizationContext(1); // 设置为我们自定义的同步上下文 SynchronizationContext.SetSynchronizationContext(mcs); mcs.Post(_ => { Test(); }, null); }); Console.ReadLine(); } static void Test() { Console.WriteLine("Test:Start"); DoSthAsync().GetAwaiter().GetResult(); Console.WriteLine("Test:END"); } static async Task DoSthAsync() { Console.WriteLine("DoSthAsync: START"); await Task.Delay(100); Console.WriteLine("DoSthAsync: END"); } ``` tn2>由于最大等待数量为1,所以当我们第二次在Task.Delay的时候就会被阻塞起。 ![](https://img.tnblog.net/arcimg/hb/b0c0dcb7b0f2417eaa9c164a63b7200e.png) tn2>而之前我们看到的`.ConfigureAwait(continueOnCapturedContext:false);`,这段代码的意思就是:不管你有没有同步上下文我都会到TaskScheduler上去执行。 ```csharp static void Main(string[] args) { Task.Run(() => { var mcs = new MaxConcurrencySynchronizationContext(1); // 设置为我们自定义的同步上下文 SynchronizationContext.SetSynchronizationContext(mcs); mcs.Post(_ => { Test(); }, null); }); Console.ReadLine(); } static void Test() { Console.WriteLine("Test:Start"); DoSthAsync().GetAwaiter().GetResult(); Console.WriteLine("Test:END"); } static async Task DoSthAsync() { Console.WriteLine("DoSthAsync: START"); await Task.Delay(100).ConfigureAwait(false); Console.WriteLine("DoSthAsync: END"); } ``` ![](https://img.tnblog.net/arcimg/hb/2d5defd244ae46078cdf8b589a8257a8.png) ValueTask ------------ tn2>ValueTask与Task类似,但它是值类型的。`ValueTask<TResult>`提供了一个AsTask方法,可根据需要获取的常规task(例如用作Task.WhenAll或Task.WhenAny调用的某个元素),不过多数情况下只是安装普通task那样调用await操作。<br/> `ValueTask<TResult>`相比于`Task<TResult>`优势何在?其实体现在堆内存分配和垃圾回收上。`Task<TResult>`是一个类,虽然有时异步基础架构会复用已创建的`Task<TResult>`对象。但多数async方法需要创建新的`Task<TResult>`对象。一般情况下,.NET创建对象的性能消耗不足为虑,但如果频繁创建对象或者遇到性能敏感的代码,就需要尽量避免创建新对象。<br/> 如果在async方法中对某个尚未完成的操作使用await,那么创建对象是不可避免的,虽然此时方法会立即返回,但它需要安排一个延续。当操作完成时,该延续负责执行async方法中的其他语句。大部分async方法中的操作不会在await前执行完成。此时使用使用`ValueTask<TResult>`没有任何优势,可能还会导致性能下降。<br/> 有时task在await之前便已完成,这个时候就能体现出`ValueTask<TResult>`的强大了 ```csharp public sealed class ByteStream : IDisposable { private readonly Stream stream; private readonly byte[] buffer; private int position; private int bufferedBytes; public ByteStream(Stream stream) { this.stream = stream; // 8KB 缓冲区的大小,根本不需要await操作 buffer = new byte[1024 * 8]; } public async ValueTask<byte?> ReadByteAsync() { if (position == bufferedBytes) { position = 0; // 读取数据且不需要同步上下文执行 bufferedBytes = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); // 读到末尾了 if (bufferedBytes == 0) { return null; } } // 返回缓冲区的下一个字节 return buffer[position++]; } public void Dispose() { stream.Dispose(); } } ``` ![](https://img.tnblog.net/arcimg/hb/5376056179a14518af96ae0dc7fbd6fc.png) tn>主要参考于黄凯华老师老师的演讲:https://www.bilibili.com/video/BV1K3411r75N?p=5 其他文献: 《C#深入浅出(第四版)》 Setephen Toub的:https://devblogs.microsoft.com/pfxteam/executioncontext-vs-synchronizationcontext/ Sergey:https://devblogs.microsoft.com/premier-developer/extending-the-async-methods-in-c/ https://stackoverflow.com/questions/50059704/implementing-async-return-types-on-net-standard
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
👈{{preArticle.title}}
👉{{nextArticle.title}}
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}
尘叶心繁
这一世以无限游戏为使命!
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
.net后台框架
166篇
linux
17篇
linux中cve
1篇
windows中cve
0篇
资源分享
10篇
Win32
3篇
前端
28篇
传说中的c
4篇
Xamarin
9篇
docker
15篇
容器编排
101篇
grpc
4篇
Go
15篇
yaml模板
1篇
理论
2篇
更多
Sqlserver
4篇
云产品
39篇
git
3篇
Unity
1篇
考证
2篇
RabbitMq
23篇
Harbor
1篇
Ansible
8篇
Jenkins
17篇
Vue
1篇
Ids4
18篇
istio
1篇
架构
2篇
网络
7篇
windbg
4篇
AI
18篇
threejs
2篇
人物
1篇
嵌入式
2篇
python
13篇
HuggingFace
8篇
pytorch
9篇
opencv
6篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2024
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术