当前位置: 首页 > news >正文

网站做SEO优化网站建设公司与维护

网站做SEO优化,网站建设公司与维护,网络推广怎样做,北京网站建设制作哪家公司好一#xff1a;背景 1. 讲故事前几天在项目中用 MemoryStream 的时候意外发现 ReadAsync 方法多了一个返回 ValueTask 的重载#xff0c;真是日了狗了#xff0c;一个 Task 已经够学了#xff0c;又来一个 ValueTask#xff0c;晕#xff0c;方法签名如下#xff1a;publ… 一背景 1. 讲故事前几天在项目中用 MemoryStream 的时候意外发现 ReadAsync 方法多了一个返回 ValueTask 的重载真是日了狗了一个 Task 已经够学了又来一个 ValueTask晕方法签名如下public class MemoryStream : Stream{public override ValueTaskint ReadAsync(Memorybyte buffer, CancellationToken cancellationToken  default(CancellationToken)){}}既然是新玩意我就比较好奇看看这个 ValueTask 是个啥玩意翻翻源码看看类定义public readonly struct ValueTaskTResult : IEquatableValueTaskTResult{}原来是搞了一个 值类型的Task无数的优化经验告诉我值类型相比引用类型要节省空间的多不信的话可以用 windbg 去校验一下分别在 List 中灌入 1000 个Task 和 1000 个 ValueTask看看所占空间大小。 0:000 !clrstack -l OS Thread Id: 0x44cc (0)Child SP               IP Call Site 0000004DA3B7E630 00007ffaf84329a6 ConsoleApp2.Program.Main(System.String[]) [E:\net5\ConsoleApp1\ConsoleApp2\Program.cs  17]LOCALS:0x0000004DA3B7E6E8  0x000001932896ac780x0000004DA3B7E6E0  0x000001932897e700 0:000 !objsize 0x000001932896ac78 sizeof(000001932896AC78)  80056 (0x138b8) bytes (System.Collections.Generic.List1[[System.Threading.Tasks.Task1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib]]) 0:000 !objsize 0x000001932897e700 sizeof(000001932897E700)  16056 (0x3eb8) bytes (System.Collections.Generic.List1[[System.Threading.Tasks.ValueTask1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib]])上面的代码可以看出 1000 个 Task 需占用 80056 byte1000 个 ValueTask 需占用 16056 byte相差大概 5 倍空间利用率确实得到了大大提升除了这个 ValueTask 还想解决什么问题呢二ValueTask 原理分析 1. 从 MemoryStream 中寻找答案大家可以仔细想一想既然 MemoryStream 中多了一个 ReadAsync 扩展必然是现存的 ReadAsync 不能满足某些业务那不能满足什么业务呢只能从方法源码中寻找答案简化后的代码如下 public override Taskint ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) {if (cancellationToken.IsCancellationRequested){return Task.FromCanceledint(cancellationToken);}int num  Read(buffer, offset, count);Taskint lastReadTask  _lastReadTask;return (lastReadTask ! null  lastReadTask.Result  num) ? lastReadTask : (_lastReadTask  Task.FromResult(num)); }看完这段代码不知道大家有没有什么疑惑反正我是有疑惑的。2. 我的疑惑1) 异步 竟然包装了 cpu 密集型操作C# 引入异步本质上是用来解决 IO 密集型 的场景利用磁盘驱动器的强势介入进而释放了调用线程提高线程的利用率和吞吐率而恰恰这里的 ReadAsync 中的 Read 其实是一个简单的纯内存操作也就是 CPU 密集型 的场景这个时候用异步来处理其实没有任何效果可言说严重一点就是为了异步而异步或许就是为了统一异步编程模型吧。2) CPU 密集型处理速度瞬息万里纯内存操作速度是相当快的1s内可达千万次执行那有什么问题呢这问题大了大家看清楚了这个 ReadAsync 返回的是一个 Task 对象这就意味着瞬间会在托管堆中生成千万个 Task 对象造成的后果可能就是 GC 不断痉挛严重影响程序的性能。3. 语言团队的解决方案可能基于我刚才聊到的二点尤其是第二点语言团队给出了 ValueTask 这个解决方案毕竟它是值类型也就不会在托管堆上分配任何内存和GC就没有任何关系了有些朋友会说空口无凭Talk is cheap. Show me the code 。三Task 和 ValueTask 在 MemoryStream 上的演示 1. Task的 ReadAsync 演示为了方便讲解我准备灌入一段文字到 MemoryStream 中去然后再用 ReadAsync 一个 byte 一个 byte 的读出来目的就是让 while 多循环几次多生成一些Task对象,代码如下class Program{static void Main(string[] args){var content  GetContent().Result;Console.WriteLine(content);Console.ReadKey();}public static async Taskstring GetContent(){string str   一般情况是学生不在意草稿纸摆放在桌上的位置他通常不会把纸摆正总是顺手在空白处演算杂乱无序。但是我曾见到有位学生在草稿纸上按顺序编号。他告诉我这样做的好处是无论是考试还是做作业在最后检验时根据编号他很快就能找到先前的演算过程这样大概可以省下两三分钟。这个习惯可能会跟着他一辈子他的一生中可以有无数个两三分钟而且很可能会有几次关键的两三分钟。;using (MemoryStream ms  new MemoryStream(Encoding.UTF8.GetBytes(str))){byte[] bytes  new byte[1024];ms.Seek(0, SeekOrigin.Begin);int cursor  0;var offset  0;int count  1;while ((offset  await ms.ReadAsync(bytes, cursor, count)) ! 0){cursor  offset;}return Encoding.UTF8.GetString(bytes, 0, cursor);}}}输出结果是没有任何问题的接下来用 windbg 看一看托管堆上生成了多少个 Task。。。 0:000 !dumpheap -type Task -stat Statistics:MT    Count    TotalSize Class Name 00007ffaf2404650        1           24 System.Threading.Tasks.Taskc 00007ffaf24042b0        1           40 System.Threading.Tasks.TaskFactory 00007ffaf23e3848        1           64 System.Threading.Tasks.Task 00007ffaf23e49d0        1           72 System.Threading.Tasks.Task1[[System.String, System.Private.CoreLib]] 00007ffaf23e9658        2          144 System.Threading.Tasks.Task1[[System.Int32, System.Private.CoreLib]] Total 6 objects从托管堆上看我去Taskint 为啥只有两个呢????????了难道我推演错啦不可能的看看源码去。 public override Taskint ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) {int num  Read(buffer, offset, count);Taskint lastReadTask  _lastReadTask;return (lastReadTask ! null  lastReadTask.Result  num) ? lastReadTask : (_lastReadTask  Task.FromResult(num)); }上面最后一句代码不知道大家有没有看懂MemoryStream 用了 _lastReadTask 玩了一个小技巧只要 num 相同返回的都是一个 Task如果不同则会生成新的 Task 对象显然这是根据特定场景进行优化的为了普适性我肯定要绕过这个技巧做法就是每次 num 数字不一样就可以了将 while 修改成代码如下while ((offset  await ms.ReadAsync(bytes, cursor, count % 2  0 ? 1 : 2)) ! 0){cursor  offset;}然后再用 windbg 看一下 0:000 !dumpheap -type Task -stat Statistics:MT    Count    TotalSize Class Name 00007ffaf7f04650        1           24 System.Threading.Tasks.Taskc 00007ffaf7f042b0        1           40 System.Threading.Tasks.TaskFactory 00007ffaf7ee3848        1           64 System.Threading.Tasks.Task 00007ffaf7ee49d0        1           72 System.Threading.Tasks.Task1[[System.String, System.Private.CoreLib]] 00007ffaf7ee9658      371        26712 System.Threading.Tasks.Task1[[System.Int32, System.Private.CoreLib]] Total 375 objects从最后一行代码可以看到 Count371哈哈这要是千万级的那这里的 Task 有多恐怖可想而知哈。2. ValueTask的 ReadAsync 演示前面例子的危害性大家也清楚了这种场景下解决方案自然就是C#团队提供的新 ReadAsync 方法代码如下class Program{static void Main(string[] args){var content  GetContent().Result;Console.WriteLine(content);Console.ReadKey();}public static async Taskstring GetContent(){string str   一般情况是学生不在意草稿纸摆放在桌上的位置他通常不会把纸摆正总是顺手在空白处演算杂乱无序。但是我曾见到有位学生在草稿纸上按顺序编号。他告诉我这样做的好处是无论是考试还是做作业在最后检验时根据编号他很快就能找到先前的演算过程这样大概可以省下两三分钟。这个习惯可能会跟着他一辈子他的一生中可以有无数个两三分钟而且很可能会有几次关键的两三分钟。;using (MemoryStream ms  new MemoryStream(Encoding.UTF8.GetBytes(str))){byte[] bytes  new byte[1024];Memorybyte memory  new Memorybyte(bytes);ms.Seek(0, SeekOrigin.Begin);int cursor  0;var offset  0;var count  1;while ((offset  await ms.ReadAsync(memory.Slice(cursor, count % 2  0 ? 1 : 2))) ! 0){cursor  offset;}return Encoding.UTF8.GetString(bytes, 0, cursor);}}}很开心用 ValueTask 也实现了同样的功能而且还不给 GC 添任何麻烦不信的话用windbg 校验下 0:000 !dumpheap -type Task -stat Statistics:MT    Count    TotalSize Class Name 00007ffaf23f7bf0        1           24 System.Threading.Tasks.Taskc 00007ffaf23f7850        1           40 System.Threading.Tasks.TaskFactory 00007ffaf23c3848        1           64 System.Threading.Tasks.Task 00007ffaf23c49d0        1           72 System.Threading.Tasks.Task1[[System.String, System.Private.CoreLib]] Total 4 objects0:000 !dumpheap -type ValueTask -stat Statistics:MT    Count    TotalSize Class Name Total 0 objects可以看到托管堆上没有任何踪迹简直就是完美。四ValueTask 真的完美吗 如果真是完美的话我相信底层框架中都会改成 ValueTask而现实并没有也就说明 ValueTask 只是某一些场景下的优选方案如果你明白了上面两个案例你应该会明白 ValueTask 特别适合于那些 CPU 密集型的 异步任务因为是个假异步当你 await 的时候其实结果已经出来了毕竟人家是纯内存操作不和底层的驱动器打交道速度自然相当快。struct 在多线程模式下有很多种限制如果用的不当会有太多的潜在问题和不确定性你可以想一想为啥 lock 锁中大多会用引用类型而不是值类型其实是一样的道理所以它注定是一个高阶玩法相信 95% 的朋友在项目开发中都不会用到用用 Task 就好了基本包治百病 ????????????五总结 从 ValueTask 要解决的问题上可以看出C#语言团队对高并发场景下的性能优化已经快走火入魔了而且现有类库中 99% 的方法还是采用 Task所以普通玩家还是老老实实的用 Task 吧现实中还没有遇到在这个上面碰到性能瓶颈的高能的还是留给高阶玩家吧
http://www.pierceye.com/news/323272/

相关文章:

  • 单页网站有后台搜索引擎优化工具有哪些
  • 视频网站弹幕怎么做中小企业网站优化
  • 南充网站建设江宁外贸网站建设
  • 从事网站开发需要的证书泰安百度推广代理
  • 找工作哪个网站好2022查询网站备案显示划横线
  • 06627网页制作和网站建设如何制作自己的公司内部网站
  • 网站营销与推广方案百度大数据分析
  • 手机怎么做自己的网站做网站的公司广州
  • asp.net网站开发案例教程南京seo排名
  • 购物网站开发技术分销
  • 企业网站建设专家工业产品设计包括哪些
  • 潍坊网站开发高手重庆市设计院
  • 微信公众号平台网站开发WordPress破解分享
  • 东营网站建设服务商低价备案域名购买
  • 高校网站建设自查报告哪个外贸网站开发客户比较好用
  • 网站做付费推广都需要问什么wordpress小工具插件
  • 网站的建设技术有哪些北京一环都是住什么人
  • 做外贸soho网站的公司吗已有备案号新增网站备案要关闭原先的站点吗
  • 网站域名注册免费wordpress 让导航悬浮
  • 全景旅游网站项目建设湖南建筑公司网站
  • 做网批那个网站好免费视频素材库app
  • cms建站模板appseo网络优化是什么工作
  • 云落wordpress优化大师在哪里
  • 威海网站建设公司手机网站做落地页
  • 海宁建设局网站三网合一 网站建设
  • 1688货源网官方网站网站怎么做背景
  • 做阿里还是网站中小企业为什么要建设网站
  • 天津的网站建设做网站费用怎么入账
  • 网站原型是产品经理做wordpress手机上用的
  • 专业网站排名优化重庆广告公司电话