辽宁网站建设,广西手机响应式网站建设公司,江苏网站建设电话,临沂市建设局网站公示最近在为 Newbe.Claptrap 做性能升级#xff0c;因此将过程中使用到的 dotTrace 软件的基础用法介绍给各位开发者。Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架。如果您是首次阅读本系列文章。建议可以先从本文末尾的入门文章开始了解。开篇摘要dotTrace 是 J… 最近在为 Newbe.Claptrap 做性能升级因此将过程中使用到的 dotTrace 软件的基础用法介绍给各位开发者。Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架。如果您是首次阅读本系列文章。建议可以先从本文末尾的入门文章开始了解。开篇摘要dotTrace 是 Jetbrains 公司为 .net 应用提供的一款 profile 软件。有助于对于软件中的耗时函数和内存问题进行诊断分析。本篇我们将使用 Jetbrains 公司的 dotTrace 软件对一些已知的性能问题进行分析。从而使读者能够掌握使用该软件的基本技能。过程中我们将搭配一些经典的面试问题进行演示逐步解释该软件的使用。此次示例使用的是 Rider 作为主要演示的 IDE。开发者也可以使用 VS Resharper 做出相同的效果。如何获取 dotTracedotTrace 是付费软件。目前只要购买 dotUltimate 及以上的许可证便可以直接使用该软件。当然该软件也包含试用版本可以免费开启 7 天的试用时间。Jetbrains 的 IDE 购买满一年以上即可获取一个当前最新的永久使用版本。或者也可以直接购买 Jetbrains 全家桶许可证一次性全部带走。经典场景再现接下来我们通过一些经典的面试问题来体验一下如何使用 dotTrace。何时要使用 StringBuilder这是多么经典的面试问题。能够看到这篇文章的朋友我相信各位都知道 StringBuilder 能够减少 string 直接拼接的碎片减少内存压力这个道理。我们这是真的吗会不会只是面试官想要刁难我欺负我信息不对称呢没有关系接下来让我们使用 dotTrace 来具体的结合代码来分析一波。看看使用 StringBuilder 究竟有没有减低内存分配的压力。首先我们创建一个单元测试项目并添加以下这样一个测试类using System.Linq;
using System.Text;
using NUnit.Framework;namespace Newbe.DotTrace.Tests
{public class X01StringBuilderTest{[Test]public void UsingString(){var source Enumerable.Range(0, 10).Select(x x.ToString()).ToArray();var re string.Empty;for (int i 0; i 10_000; i){re source[i % 10];}}[Test]public void UsingStringBuilder(){var source Enumerable.Range(0, 10).Select(x x.ToString()).ToArray();var sb new StringBuilder();for (var i 0; i 10_000; i){sb.Append(source[i % 10]);}var _ sb.ToString();}}
}
然后如下图所示我们将 Rider 中的 profile 模式设置为 Timeline 。TimeLine 是多种模式中的一种相较而言该模式可以更全面的了解各个线程的工作情况包括有内存分配、IO 处理、锁、反射等等多维度数据。这将会作为本示例主要使用的一种模式。接着如下图所示通过单元测试左侧的小图标启动对应测试的 profile。启动 profile 之后等待一段时间之后便会出现最新生成的 timeline 报告。查看报告的位置如下所示右键选择对应的报告选择”Open in External Viewer”便可以使用 dotTrace 打开生成好的报告。那么首先让我打开第一个报告查看 UsingString 方法生成的报告。如下图所示选择 .Net Memory Allocations 以查看该测试运行过程中分配的内存数额。根据上图我们可以得出以下结论在这测试中有 102M 的内存被分配给 String 。注意在 dotTrace 中显示的分配是指整个运行过程中全部分配的内存。即使后续被回收该数值也不会减少。内存的分配只要在 CLR Worker 线程进行。并且非常的密集。TipTimeline 所显示的运行时间比正常运行测试的时间更长因为在 profile 过程中需要对数据进行记录会有额外的消耗。因此我们就得出了第一个结论使用 string 进行直接拼接确实会消耗更多的内存分配。接着我们继续按照上面的步骤查看一下 UsingStringBuilder 方法的报告如下所示根据上图我们可以得出第二个结论使用 StringBuilder 可以明显的减少相较于 string 直接拼接所消耗的内存。当然我们得到的最终的结论其实是看来面试官不是糊弄人。class 和 struct 对内存有什么影响class 和 struct 的区别有很多面试题常客了。其中两者在内存方面就存在区别。那么我们通过一个测试来看看区别。using System;
using System.Collections.Generic;
using NUnit.Framework;namespace Newbe.DotTrace.Tests
{public class X02ClassAndStruct{[Test]public void UsingClass(){Console.WriteLine($memory in bytes before execution: {GC.GetGCMemoryInfo().TotalAvailableMemoryBytes});const int count 1_000_000;var list new ListStudent(count);for (var i 0; i count; i){list.Add(new Student{Level int.MinValue});}list.Clear();var gcMemoryInfo GC.GetGCMemoryInfo();Console.WriteLine($heap size: {gcMemoryInfo.HeapSizeBytes});Console.WriteLine($memory in bytes end of execution: {gcMemoryInfo.TotalAvailableMemoryBytes});}[Test]public void UsingStruct(){Console.WriteLine($memory in bytes before execution: {GC.GetGCMemoryInfo().TotalAvailableMemoryBytes});const int count 1_000_000;var list new ListYueluo(count);for (var i 0; i count; i){list.Add(new Yueluo{Level int.MinValue});}list.Clear();var gcMemoryInfo GC.GetGCMemoryInfo();Console.WriteLine($heap size: {gcMemoryInfo.HeapSizeBytes});Console.WriteLine($memory in bytes end of execution: {gcMemoryInfo.TotalAvailableMemoryBytes});}public class Student{public int Level { get; set; }}public struct Yueluo{public int Level { get; set; }}}
}
代码要点两个测试分别创建 1,000,000 个 class 和 struct 加入到 List 中。运行测试之后在测试的末尾输出当前堆空间的大小。按照上一节提供的基础步骤我们对比两个方法生成的报告。UsingClassUsingStruct对比两个报告可以得出以下这些结论Timeline 报告中的内存分配只包含分配在堆上的内存情况。struct 不需要分配在堆上但是数组是引用对象需要分配在堆上。List 自增的过程本质是扩张数组的特性在报告中也得到了体现。另外没有展示在报告上而展示在测试打印文本中可以看到UsingStruct 运行之后的堆大小也证实了 struct 不会被分配在堆上。装箱和拆箱经典面试题 X3来上代码上报告using NUnit.Framework;namespace Newbe.DotTrace.Tests
{public class X03Boxing{[Test]public void Boxing(){for (int i 0; i 1_000_000; i){UseObject(i);}}[Test]public void NoBoxing(){for (int i 0; i 1_000_000; i){UseInt(i);}}public static void UseInt(int age){// nothing}public static void UseObject(object obj){// nothing}}
}
Boxing, 发生装箱拆箱NoBoxing未发生装箱拆箱对比两个报告可以得出以下这些结论没有买卖就没有杀害没有装拆就没有分配消耗。Thread.Sleep 和 Task.Delay 有什么区别经典面试题 X4来上代码上报告using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;namespace Newbe.DotTrace.Tests
{public class X04SleepTest{[Test]public Task TaskDelay(){return Task.Delay(TimeSpan.FromSeconds(3));}[Test]public Task ThreadSleep(){return Task.Run(() { Thread.Sleep(TimeSpan.FromSeconds(3)); });}}
}
ThreadSleepTaskDelay对比两个报告可以得出以下这些结论在 dotTrace 中 Thread.Sleep 会被单独标记因为这是一种性能不不佳的做法容易造成线程饥饿。Thread.Sleep 比起 Task.Delay 会多出一个线程处于 Sleep 状态阻塞大量的 Task 真的会导致应用一动不动吗有了上一步的结论笔者产生了一个大胆的想法。我们都知道线程的有限的那如果启动非常多的 Thread.Sleep 或者 Task.Delay 会如何呢来代码using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;namespace Newbe.DotTrace.Tests
{public class X04SleepTest{[Test]public Task RunThreadSleep(){return Task.WhenAny(GetTasks(50));IEnumerableTask GetTasks(int count){for (int i 0; i count; i){var i1 i;yield return Task.Run(() {Console.WriteLine($Task {i1});Thread.Sleep(int.MaxValue);});}yield return Task.Run(() { Console.WriteLine(yueluo is the only one dalao); });}}[Test]public Task RunTaskDelay(){return Task.WhenAny(GetTasks(50));IEnumerableTask GetTasks(int count){for (int i 0; i count; i){var i1 i;yield return Task.Run(() {Console.WriteLine($Task {i1});return Task.Delay(TimeSpan.FromSeconds(int.MaxValue));});}yield return Task.Run(() { Console.WriteLine(yueluo is the only one dalao); });}}}
}
这里就不贴报告了读者可以试一下这个测试也可以将报告的内容写在本文的评论中参与讨论反射调用和表达式树编译调用有时我们需要动态调用一个方法。最广为人知的方式就是使用反射。但是这也是广为人知的耗时相对较高的方式。这里笔者提供一种使用表达式树创建委托来取代反射提高效率的思路。那么究竟有没有减少时间消耗呢好报告自己会说话。using System;
using System.Diagnostics;
using System.Linq.Expressions;
using NUnit.Framework;namespace Newbe.DotTrace.Tests
{public class X05ReflectionTest{[Test]public void RunReflection(){var methodInfo GetType().GetMethod(nameof(MoYue));Debug.Assert(methodInfo ! null, nameof(methodInfo) ! null);for (int i 0; i 1_000_000; i){methodInfo.Invoke(null, null);}Console.WriteLine(_count);}[Test]public void RunExpression(){var methodInfo GetType().GetMethod(nameof(MoYue));Debug.Assert(methodInfo ! null, nameof(methodInfo) ! null);var methodCallExpression Expression.Call(methodInfo);var lambdaExpression Expression.LambdaAction(methodCallExpression);var func lambdaExpression.Compile();for (int i 0; i 1_000_000; i){func.Invoke();}Console.WriteLine(_count);}private static int _count 0;public static void MoYue(){_count;}}
}
RunReflection直接使用反射调用。RunExpression使用表达式树编译一个委托。本篇小结使用 dotTrace 可以查看方法的内存和时间消耗。本篇所演示的内容只是其中很小的部分。开发者们可以尝试上手大有裨益。本篇内容中的示例代码均可以在以下链接仓库中找到https://github.com/newbe36524/Newbe.Demohttps://gitee.com/yks/Newbe.Demo最后但是最重要如果读者对该内容感兴趣欢迎转发、评论、收藏文章以及项目。最近作者正在构建以反应式、Actor模式和事件溯源为理论基础的一套服务端开发框架。希望为开发者提供能够便于开发出 “分布式”、“可水平扩展”、“可测试性高” 的应用系统 ——Newbe.Claptrap本篇文章是该框架的一篇技术选文属于技术构成的一部分。联系方式Github IssueGitee Issue公开邮箱 newbe-claptrapgooglegroups.com 发送到该邮箱的内容将被公开GitterQQ 群 610394020您还可以查阅本系列的其他选文理论入门篇Newbe.Claptrap - 一套以 “事件溯源” 和 “Actor 模式” 作为基本理论的服务端开发框架术语介绍篇Actor 模式事件溯源Event SourcingClaptrapMinion事件 Event状态 State状态快照 State SnapshotClaptrap 设计图 Claptrap DesignClaptrap 工厂 Claptrap FactoryClaptrap IdentityClaptrap BoxClaptrap 生命周期Claptrap Lifetime Scope序列化Serialization实现入门篇Newbe.Claptrap 框架入门第一步 —— 创建项目实现简易购物车Newbe.Claptrap 框架入门第二步 —— 简单业务清空购物车Newbe.Claptrap 框架入门第三步 —— 定义 Claptrap管理商品库存Newbe.Claptrap 框架入门第四步 —— 利用 Minion商品下单样例实践篇构建一个简易的火车票售票系统Newbe.Claptrap 框架用例第一步 —— 业务分析在线体验火车票售票系统其他番外篇谈反应式编程在服务端中的应用数据库操作优化从 20 秒到 0.5 秒谈反应式编程在服务端中的应用数据库操作优化提速 Upsert十万同时在线用户需要多少内存——Newbe.Claptrap 框架水平扩展实验docker-mcr 助您全速下载 dotnet 镜像十多位全球技术专家为你献上近十个小时的.Net 微服务介绍年轻的樵夫哟你掉的是这个免费 8 核 4G 公网服务器还是这个随时可用的 Docker 实验平台如何使用 dotTrace 来诊断 netcore 应用的性能问题GitHub 项目地址https://github.com/newbe36524/Newbe.ClaptrapGitee 项目地址https://gitee.com/yks/Newbe.Claptrap您当前查看的是先行发布于 www.newbe.pro 上的博客文章实际开发文档随版本而迭代。若要查看最新的开发文档需要移步 claptrap.newbe.pro。