.NET Core 中的性能

.NET Core 中的性能

.NET Core 中的性能

大家好! 本文是我和我的同事在处理不同项目时长期使用的最佳实践的集合。

有关执行计算的机器的信息:BenchmarkDotNet=v0.11.5,操作系统=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R),1 个 CPU,8 个逻辑核心和 4 个物理核心
.NET核心SDK=3.0.100
[主机]:.NET Core 2.2.7(CoreCLR 4.6.28008.02、CoreFX 4.6.28008.03)、64位RyuJIT
核心:.NET Core 2.2.7(CoreCLR 4.6.28008.02、CoreFX 4.6.28008.03)、64 位 RyuJIT
[主机]:.NET Core 3.0.0(CoreCLR 4.700.19.46205、CoreFX 4.700.19.46214)、64位RyuJIT
核心:.NET Core 3.0.0(CoreCLR 4.700.19.46205、CoreFX 4.700.19.46214)、64 位 RyuJIT

作业=核心运行时=核心

ToList 与 ToArray 和循环


我本来打算在.NET Core 3.0发布时准备这些信息,但他们抢先了我,我不想窃取别人的荣耀并复制别人的信息,所以我只是指出 链接到一篇好文章,其中详细描述了比较.

就我个人而言,我只想向您展示我的测量结果和结果;我为“C++ 风格”编写循环的爱好者添加了反向循环。

代码:

public class Bench
    {
        private List<int> _list;
        private int[] _array;

        [Params(100000, 10000000)] public int N;

        [GlobalSetup]
        public void Setup()
        {
            const int MIN = 1;
            const int MAX = 10;
            Random random = new Random();
            _list = Enumerable.Repeat(0, N).Select(i => random.Next(MIN, MAX)).ToList();
            _array = _list.ToArray();
        }

        [Benchmark]
        public int ForList()
        {
            int total = 0;
            for (int i = 0; i < _list.Count; i++)
            {
                total += _list[i];
            }

            return total;
        }
        
        [Benchmark]
        public int ForListFromEnd()
        {
            int total = 0;t
            for (int i = _list.Count-1; i > 0; i--)
            {
                total += _list[i];
            }

            return total;
        }

        [Benchmark]
        public int ForeachList()
        {
            int total = 0;
            foreach (int i in _list)
            {
                total += i;
            }

            return total;
        }

        [Benchmark]
        public int ForeachArray()
        {
            int total = 0;
            foreach (int i in _array)
            {
                total += i;
            }

            return total;
        }

        [Benchmark]
        public int ForArray()
        {
            int total = 0;
            for (int i = 0; i < _array.Length; i++)
            {
                total += _array[i];
            }

            return total;
        }
        
        [Benchmark]
        public int ForArrayFromEnd()
        {
            int total = 0;
            for (int i = _array.Length-1; i > 0; i--)
            {
                total += _array[i];
            }

            return total;
        }
    }

.NET Core 2.2 和 3.0 中的速度几乎相同。 以下是我在 .NET Core 3.0 中能够获得的内容:

.NET Core 中的性能

.NET Core 中的性能

我们可以得出结论,由于其内部优化和显式集合大小分配,数组集合的迭代处理速度更快。 还值得记住的是,List 集合有其自身的优点,您应该根据所需的计算使用正确的集合。 即使您编写了使用循环的逻辑,也不要忘记这是一个普通的循环,并且它也可能受到循环优化的影响。 habr上很久以前就发表过一篇文章: https://habr.com/ru/post/124910/。 它仍然具有相关性并推荐阅读。

一年前,我在一家公司的一个遗留项目中工作,在该项目中,通过 try-catch- throw 结构来处理字段验证是正常的。 当时我已经明白这对于项目来说是不健康的业务逻辑,所以只要有可能我就尽量不使用这样的设计。 但让我们弄清楚为什么用这种结构处理错误的方法是不好的。 我编写了一个小代码来比较这两种方法,并为每个选项制定了基准。

代码:

        public bool ContainsHash()
        {
            bool result = false;
            foreach (var file in _files)
            {
                var extension = Path.GetExtension(file);
                if (_hash.Contains(extension))
                    result = true;
            }

            return result;
        }

        public bool ContainsHashTryCatch()
        {
            bool result = false;
            try
            {
                foreach (var file in _files)
                {
                    var extension = Path.GetExtension(file);
                    if (_hash.Contains(extension))
                        result = true;
                }
                
                if(!result) 
                    throw new Exception("false");
            }
            catch (Exception e)
            {
                result = false;
            }

            return result;
        }

.NET Core 3.0 和 Core 2.2 中的结果有类似的结果(.NET Core 3.0):

.NET Core 中的性能

.NET Core 中的性能

Try catch 会使代码更难理解并增加程序的执行时间。 但如果您需要这种构造,则不应插入那些预计不会处理错误的代码行 - 这将使代码更易于理解。 事实上,加载系统的并不是对异常的处理,而是通过 throw new Exception 构造抛出错误本身。

抛出异常比某些以所需格式收集错误的类要慢。 如果您正在处理表单或某些数据,并且您清楚地知道错误应该是什么,为什么不处理它呢?

如果这种情况并非异常,则不应编写 throw new Exception() 构造。 处理和抛出异常是非常昂贵的!

ToLower、ToLowerInvariant、ToUpper、ToUpperInvariant

在我 5 年的 .NET 平台工作经验中,我遇到过许多使用字符串匹配的项目。 我还看到了下面的图片:有一个企业解决方案有很多项目,每个项目执行字符串比较的方式都不同。 但应该使用什么以及如何统一呢? 在Richter的《CLR via C#》一书中,我读到ToUpperInvariant()方法比ToLowerInvariant()方法更快的信息。

书中摘录:

.NET Core 中的性能

当然,我不相信,决定在 .NET Framework 上运行一些测试,结果让我震惊——性能提升了 15% 以上。 然后,第二天早上上班时,我向我的上级展示了这些测量结果,并允许他们访问源代码。 此后,2 个项目中有 14 个进行了更改以适应新的测量,考虑到这两个项目的存在是为了处理巨大的 Excel 表,结果对于产品来说意义重大。

我还向大家展示了不同版本的 .NET Core 的测量结果,以便大家可以选择最佳的解决方案。 我只想补充一点,在我工作的公司中,我们使用 ToUpper() 来比较字符串。

代码:

public const string defaultString =  "VXTDuob5YhummuDq1PPXOHE4PbrRjYfBjcHdFs8UcKSAHOCGievbUItWhU3ovCmRALgdZUG1CB0sQ4iMj8Z1ZfkML2owvfkOKxBCoFUAN4VLd4I8ietmlsS5PtdQEn6zEgy1uCVZXiXuubd0xM5ONVZBqDu6nOVq1GQloEjeRN8jXrj0MVUexB9aIECs7caKGddpuut3";

        [Benchmark]
        public bool ToLower()
        {
            return defaultString.ToLower() == defaultString.ToLower();
        }

        [Benchmark]
        public bool ToLowerInvariant()
        {
            return defaultString.ToLowerInvariant() == defaultString.ToLowerInvariant();
        }

        [Benchmark]
        public bool ToUpper()
        {
            return defaultString.ToUpper() == defaultString.ToUpper();
        }

        [Benchmark]
        public bool ToUpperInvariant()
        {
            return defaultString.ToUpperInvariant() == defaultString.ToUpperInvariant();
        }

.NET Core 中的性能

.NET Core 中的性能

在 .NET Core 3.0 中,每个方法的增加约为 x2,并平衡了它们之间的实现。

.NET Core 中的性能

.NET Core 中的性能

层级编译

在我的上一篇文章中,我简要描述了这个功能,我想纠正和补充我的话。 多层编译可加快解决方案的启动时间,但您会牺牲部分代码将在后台编译为更优化的版本,这可能会带来少量开销。 随着 NET Core 3.0 的出现,启用了层编译的项目的构建时间已减少,并且与该技术相关的错误已得到修复。 此前,该技术会导致 ASP.NET Core 中的首次请求出错,并在多级编译模式下的首次构建期间冻结。 目前,它在 .NET Core 3.0 中默认启用,但您可以根据需要禁用它。 如果您处于团队领导、高级、中层或部门负责人的位置,那么您必须了解快速的项目开发可以增加团队的价值,并且该技术可以让您为开发人员节省时间以及项目本身的时间。

.NET 升级

升级您的 .NET Framework/.NET Core 版本。 通常,每个新版本都会提供额外的性能提升并添加新功能。

但具体有什么好处呢? 让我们看看其中的一些:

  • .NET Core 3.0 引入了 R2R 映像,这将减少 .NET Core 应用程序的启动时间。
  • 在 2.2 版本中,出现了 Tier Compilation,因此程序员将花费更少的时间启动项目。
  • 支持新的 .NET 标准。
  • 支持新版本的编程语言。
  • 优化,每个新版本都会对基础库 Collection/Struct/Stream/String/Regex 等进行优化,并进行更多改进。 如果您从 .NET Framework 迁移到 .NET Core,您将获得开箱即用的巨大性能提升。 作为示例,我附加了 .NET Core 3.0 中添加的一些优化的链接: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

.NET Core 中的性能

结论

编写代码时,值得关注项目的不同方面,并使用编程语言和平台的功能来实现最佳结果。 如果您分享与 .NET 优化相关的知识,我将非常高兴。

链接到github

来源: habr.com

添加评论