title author date CreateTime categories
C# 程序集数量对软件启动性能的影响
lindexi
2019-08-31 16:55:58 +0800
2018-10-17 9:24:3 +0800
C# 性能测试

本文通过很多的数据测试分析在一个项目引用很多个外部项目和将外部项目的类合并到一个项目之间的启动性能的不同。
通过分析知道了如果一个项目引用了很多项目,而且在启动过程会全部调用这些项目,这时的软件性能会比将这些项目的代码合并到一个项目的慢很多
本文的数据为 预编译框架,开发高性能应用 - 课程 - 微软技术暨生态大会 2018 - walterlv 提供

最近在做一个编译器相关的项目,这个项目是将多个库作为源代码的 nuget 包,这样就可以在开发的时候是使用多个不同的项目,避免项目之间耦合。编译的时候将多个项目编译为 一个 dll 提高了软件启动性能。而且通过源代码包的引用方式可以极大避免了在不同的平台迁移的难度,只要是代码兼容的,甚至代码部分不兼容可以使用宏的方式在不同的平台使用不同的代码。

为了告诉大家这个项目的用处,于是本文就使用代码创建的方式创建了很多代码,通过对比这些代码的运行可以知道将类分在多个项目,和将类放在一个项目在运行过程的性能

我通过创建两个不同的工程,第一个工程是包含一个项目,这个项目里有 5000 个空类,在启动之后会创建这 5000 个类中的 1000 个类。

第二个工程包括了 1000 个项目,每个项目有 5 个空类,这里的空类和前面项目的空类是一样的创建方法。然后再添加一个启动项目,这个启动项目引用了前面的 1000 个项目,在启动之后会创建 1000 个项目中每个项目的一个类,也就是创建了 1000 个类,只是每个类都在不同的项目。

经过了很长时间的编译,我运行了一个项目5000个类的项目,初次运行时间是 54 ms ,接下来两次运行时间分别是 52 ms 和 53 ms 时间很短。

然后运行 1000 个项目,一个项目 5 个类的项目,冷启动时间是 15246 毫秒,之后的运行时间如下

第二次 580 ms

第三次 552 ms

第四次 546 ms

第五次 563 ms

第六次 568 ms

第七次 569 ms

下面表格是对比两个工程运行时间

工程 冷启动 第二次 第三次
一个项目5000个类 54 ms 52 ms 53 ms
1000个项目,一个项目5个类 15246 ms 580 ms 552 ms

从上面表格可以看到,冷启动的性能差是 280 倍,此后的运行的性能差大概是 10 倍

然后我还测试了 1000 个项目,一个项目 1000 个类的运行时间,冷启动 22993 毫秒,热启动三次的数据是 885 毫秒,871 毫秒和 861 毫秒

测试项目的代码可以从 csdn 下载,如果没有积分请发邮件给我。如果觉得上面的数据很诡异,请自己运行一下编译一下

一个项目5000 个类-CSDN下载

在 1000 个项目,一个项目里有 5 个类-CSDN下载

创建测试项目的代码请看下面

创建一个项目这个项目里有 5000 个类,在启动之后调用这 5000 个类里的 1000 个

{% raw %}

        private static void LownearkeajooSasouStegisti()
{
var saryawpirmiGerekipoNehiti = new DirectoryInfo("MayairJowya"); saryawpirmiGerekipoNehiti.Create(); var fawniSorhaHereni = new List<string>(); var deleeTacarirouWulall = new WhairchooHerdo(); for (int gupoudigorKihirkercou = 0; gupoudigorKihirkercou < 1000; gupoudigorKihirkercou++)
{
var teaJawtu = deleeTacarirouWulall.LemgeDowbovou(); for (int mirxarJeredrairsear = 0; mirxarJeredrairsear < 5; mirxarJeredrairsear++)
{
var cicirRarsonisallJearwelxe = deleeTacarirouWulall.LemgeDowbovou(); var facoSaijeesereniXaimow = $@"
using System;
using System.Collections.Generic;
using System.Text; namespace {teaJawtu}
{{
public class {cicirRarsonisallJearwelxe}
{{
public string Foo {{ get; set; }}
}}
}}";
if (mirxarJeredrairsear == 0)
{
fawniSorhaHereni.Add(teaJawtu + "." + cicirRarsonisallJearwelxe);
} File.WriteAllText(
Path.Combine(saryawpirmiGerekipoNehiti.FullName, cicirRarsonisallJearwelxe + ".cs"),
facoSaijeesereniXaimow);
}
} var jawjearPalfokallPuwuTearbourer = new StringBuilder(); jawjearPalfokallPuwuTearbourer.Append(@"<Project Sdk=""Microsoft.NET.Sdk""> <PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup> <ItemGroup>
"); jawjearPalfokallPuwuTearbourer.Append(@" </ItemGroup> </Project>"); File.WriteAllText(Path.Combine(saryawpirmiGerekipoNehiti.FullName, "TirkalltremceFalgawCouwabupu.csproj"),
jawjearPalfokallPuwuTearbourer.ToString()); jawjearPalfokallPuwuTearbourer.Clear(); var cepepiSowneKorrer = @"using System;
using System.Diagnostics; namespace CouwharjeMerball
{
class Program
{
static void Main(string[] args)
{
var dafuWhayroubaXouma = new Stopwatch();
dafuWhayroubaXouma.Start();
var kawgeDeesearsofas = new KawgeDeesearsofas();
kawgeDeesearsofas.LurtrajaboPearbubirXinene();
dafuWhayroubaXouma.Stop();
Console.WriteLine(dafuWhayroubaXouma.ElapsedMilliseconds);
}
}
}
";
File.WriteAllText(Path.Combine(saryawpirmiGerekipoNehiti.FullName, "Program.cs"), cepepiSowneKorrer); jawjearPalfokallPuwuTearbourer.Append(@"namespace CouwharjeMerball
{
class KawgeDeesearsofas
{
public void LurtrajaboPearbubirXinene()
{
"); foreach (var ferosarTadir in fawniSorhaHereni)
{
jawjearPalfokallPuwuTearbourer.Append(" new " + ferosarTadir + "();");
jawjearPalfokallPuwuTearbourer.Append("\r\n");
} jawjearPalfokallPuwuTearbourer.Append(@" }
}
}"); File.WriteAllText(Path.Combine(saryawpirmiGerekipoNehiti.FullName, "KawgeDeesearsofas.cs"),
jawjearPalfokallPuwuTearbourer.ToString());
}

{% endraw %}

创建 1000 个项目,每个项目有 5 个类,在启动项目引用这 1000 个项目,在启动之后创建 1000 个类,这 1000 个类每个类都在不同的项目里

{% raw %}

        private static void KijeSabacher()
{
var jisqeCorenerairTurpalhee = new DirectoryInfo("StuLartearou"); jisqeCorenerairTurpalhee.Create(); var jairtallworBeakoo = new WhairchooHerdo(); List<string> geeberecereHouroudo = new List<string>(); List<string> xawsosapawTabejetai = new List<string>(); for (int qeltasmisVigallSearniste = 0; qeltasmisVigallSearniste < 1000; qeltasmisVigallSearniste++)
{
string louwebirPemtrasrereYorta = ""; var fismeerurniDawwall = jairtallworBeakoo.LemgeDowbovou(); var nemirchouDamounu = jisqeCorenerairTurpalhee.CreateSubdirectory(fismeerurniDawwall); var beltuzoKoma = @"<Project Sdk=""Microsoft.NET.Sdk""> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup> </Project>
";
xawsosapawTabejetai.Add(fismeerurniDawwall); File.WriteAllText(Path.Combine(nemirchouDamounu.FullName, fismeerurniDawwall + ".csproj"), beltuzoKoma); for (int roupairDufallne = 0; roupairDufallne < 5; roupairDufallne++)
{
var whowjallKelpirhorWirweSemjaneldroo = jairtallworBeakoo.LemgeDowbovou(); if (roupairDufallne == 0)
{
louwebirPemtrasrereYorta = fismeerurniDawwall + "." + whowjallKelpirhorWirweSemjaneldroo;
} var facoSaijeesereniXaimow = $@"
using System;
using System.Collections.Generic;
using System.Text; namespace {fismeerurniDawwall}
{{
public class {whowjallKelpirhorWirweSemjaneldroo}
{{
public string Foo {{ get; set; }}
}}
}}"; File.WriteAllText(
Path.Combine(nemirchouDamounu.FullName, whowjallKelpirhorWirweSemjaneldroo + ".cs"),
facoSaijeesereniXaimow);
} geeberecereHouroudo.Add(louwebirPemtrasrereYorta);
} var jawjearPalfokallPuwuTearbourer = new StringBuilder(); var dirceDadaipaHowbistairneeQabijel = "CouwharjeMerball";
var suleLougirwhe = jisqeCorenerairTurpalhee.CreateSubdirectory(dirceDadaipaHowbistairneeQabijel); jawjearPalfokallPuwuTearbourer.Append(@"<Project Sdk=""Microsoft.NET.Sdk""> <PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup> <ItemGroup>
"); foreach (var ciraZeajanipou in xawsosapawTabejetai)
{
jawjearPalfokallPuwuTearbourer.Append(
$@" <ProjectReference Include=""..\{ciraZeajanipou}\{ciraZeajanipou}.csproj"" />");
jawjearPalfokallPuwuTearbourer.Append("\r\n");
} jawjearPalfokallPuwuTearbourer.Append(@" </ItemGroup> </Project>"); File.WriteAllText(Path.Combine(suleLougirwhe.FullName, dirceDadaipaHowbistairneeQabijel + ".csproj"),
jawjearPalfokallPuwuTearbourer.ToString()); jawjearPalfokallPuwuTearbourer.Clear(); var cepepiSowneKorrer = @"using System;
using System.Diagnostics; namespace CouwharjeMerball
{
class Program
{
static void Main(string[] args)
{
var dafuWhayroubaXouma = new Stopwatch();
dafuWhayroubaXouma.Start();
var kawgeDeesearsofas = new KawgeDeesearsofas();
kawgeDeesearsofas.LurtrajaboPearbubirXinene();
dafuWhayroubaXouma.Stop();
Console.WriteLine(dafuWhayroubaXouma.ElapsedMilliseconds);
}
}
}
";
File.WriteAllText(Path.Combine(suleLougirwhe.FullName, "Program.cs"), cepepiSowneKorrer); jawjearPalfokallPuwuTearbourer.Append(@"namespace CouwharjeMerball
{
class KawgeDeesearsofas
{
public void LurtrajaboPearbubirXinene()
{
"); foreach (var ferosarTadir in geeberecereHouroudo)
{
jawjearPalfokallPuwuTearbourer.Append(" new " + ferosarTadir + "();");
jawjearPalfokallPuwuTearbourer.Append("\r\n");
} jawjearPalfokallPuwuTearbourer.Append(@" }
}
}"); File.WriteAllText(Path.Combine(suleLougirwhe.FullName, "KawgeDeesearsofas.cs"),
jawjearPalfokallPuwuTearbourer.ToString());
}

{% endraw %}

{% raw %}
{% endraw %}

参见

C# 程序内的类数量对程序启动的影响

C# 直接创建多个类和使用反射创建类的性能

C# 性能分析 反射 VS 配置文件 VS 预编译

预编译框架,开发高性能应用 - 课程 - 微软技术暨生态大会 2018 - walterlv

dotnet-campus/SourceYard: Add a NuGet package only for dll reference? By using dotnetCampus.SourceYard, you can pack a NuGet package with source code. By installing the new source code package, all source codes behaviors just like it is in your project.

2019-8-31-C#-程序集数量对软件启动性能的影响的更多相关文章

  1. C# 程序集数量对软件启动性能的影响

    本文通过很多的数据测试分析在一个项目引用很多个外部项目和将外部项目的类合并到一个项目之间的启动性能的不同. 通过分析知道了如果一个项目引用了很多项目,而且在启动过程会全部调用这些项目,这时的软件性能会 ...

  2. OSCHINA 公布 2019 年度最受欢迎中国开源软件

    https://www.oschina.net/project 此文章从此处转载:https://www.oschina.net/project/top_cn_2019?utm_source=star ...

  3. agentzh 的 Nginx 教程(版本 2019.07.31)

    agentzh 的 Nginx 教程(版本 2019.07.31) agentzh 的 Nginx 教程(版本 2019.07.31) https://openresty.org/download/a ...

  4. 2019 第十届蓝桥杯大赛软件类省赛 Java A组 题解

    2019 第十届蓝桥杯大赛软件类省赛 Java A组 试题A 题解 ​ 题目最后一句贴心的提示选手应该使用 long (C/C++ 应该使用 long long). ​ 本题思路很直白,两重循环.外层 ...

  5. C# 程序内的类数量对程序启动的影响

    原文:C# 程序内的类数量对程序启动的影响 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http://lindexi.gitee.i ...

  6. 2018-10-31-C#-程序内的类数量对程序启动的影响

    title author date CreateTime categories C# 程序内的类数量对程序启动的影响 lindexi 2018-10-31 14:7:6 +0800 2018-10-1 ...

  7. OSGi 对软件复杂度的影响

    出自 深度理解 osgi equinox 原理 1.2.1 OSGi 能让软件开发变得更容易吗 不可否认,OSGi 的入门门槛在 Java 众多技术中算是比较高的,相对陡峭的学习曲线会 为第一次使用 ...

  8. bootchart--检测linux启动性能的软件

    bootchart--检测linux启动性能的软件 摘自http://www-128.ibm.com/developerworks/library/l-boot-faster/index.html?c ...

  9. Win10如何禁止软件运行?win10禁止软件启动的设置方法!禁止人生日历热点快讯的方法

    相信不少使用Win10系统的用户遇到过下载了一款软件进行安装后后续会有接连不断的程序安装到电脑中.他可能似乎一个大家常用的程序,在我们安装好运行的时候会通过后台偷偷下载其他应用安装到我们电脑中,导致系 ...

随机推荐

  1. MongoDB特性及使用场景

    概述 MongoDB(Humongous Database),中文意思就是巨大无比的数据库,顾名思义,MongoDB就是为处理大数据而生,以解决海量数据的存储和高效查询使用为使命.MongoDB是一款 ...

  2. 6_1.springboot2.x整合JDBC与数据源配置原理解析

    1.引言 对于数据访问层,无论是SQL还是NOSQL,Spring Boot默认采用整合 Spring Data的方式进行统一处理,添加大量自动配置,屏蔽了很多设置.引入各种xxxTemplate,x ...

  3. 11_springmvc之RESTful支持

    一.理解RESTful RESTful架构,就是一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方便,所以正得到越来越多网站的采用. RESTful(即Representational Sta ...

  4. 2019 CCPC 湖南全国邀请赛

    A. Chessboard 做法1 单纯形. 做法2 最大费用可行流问题,行列模型. 对每行建一个点,每列建一个点.物品 \(i\) 在 \((r,c)\),那么 \(r\) 向 \(c\) 连流量为 ...

  5. HDU - 2222,HDU - 2896,HDU - 3065,ZOJ - 3430 AC自动机求文本串和模式串信息(模板题)

    最近正在学AC自动机,按照惯例需要刷一套kuangbin的AC自动机专题巩固 在网上看过很多模板,感觉kuangbin大神的模板最为简洁,于是就选择了用kuangbin大神的模板. AC自动机其实就是 ...

  6. chown命令使用

    1.原文件为root权限,改为用户所属权限包括文件夹以下的目录这里必须有R chown -R usrname:username /file 2.修改 tmp 目录为可写权限 chmod -R 777 ...

  7. unity3d入门 Demo 学习记录

    闲来学习一下 unity3d 的Demo,记录如下. 官方 Demo,名字为 Roll-A-Ball,如图 场景比较简单,包含地面.玩家精灵.主摄像机.墙壁.可拾取的方块.分数为示 text.平行光源 ...

  8. [转]C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  9. UVA - 374

    https://vjudge.net/problem/19685/origin 费马小定理优化快速幂 因为加了费马小定理优化,小心2 2 2这种情况,会出现0 0 2,也就是0的0次方,实际答案为0 ...

  10. 解决element 分页组件,搜索过后current-page 绑定的数据变了,但是页面当前页码并没有变的问题

    前言上一篇写前台解决分页问题的时候没有这个问题,但是在实际项目后台中有遇到过,所以在这里专门说一下,如果参考前台分页出现这种问题了,也可以使用这种方法!bug:vue和element实现的后台分页,当 ...