2

我正在处理一个代码存在性能问题的项目。

我有一些我认为会提高性能的更改,但没有真正的方法来衡量我的更改如何影响它。

我编写了一个单元测试,它按照当前实现的方式执行操作,并Stopwatch监控函数运行的速度。我还写了一个类似的单元测试,它做的事情略有不同。

如果测试一起运行,一个需要 1 秒完成,另一个需要 73 毫秒。如果测试是分开运行的,它们都需要大约 1 秒才能完成(是的.. 我所做的改变似乎并没有太大变化)。

如果测试相同,我有同样的问题,一个比另一个运行得快。

Visual Studio 是否在幕后做一些事情来提高性能?如果是,我可以关闭它吗?

我尝试将测试移动到不同的文件中,但这并没有解决我遇到的问题。

我希望能够运行所有测试,但让它们像一次只运行一个测试一样运行。

4

2 回答 2

3

我的猜测:很可能是 dll 加载和 JIT 编译

1. 装配装载。

.NET 延迟加载程序集(dll)。如果您添加对 FooLibrary 的引用,这并不意味着它会在您的代码加载时被加载。相反,当你第一次从 FooLibrary 调用一个函数或实例化一个类时,CLR将去加载它所在的 dll。这涉及在文件系统中搜索它,可能的安全检查等。
如果你代码甚至中等复杂,那么“第一次测试”通常最终会导致加载数十个程序集,这显然需要一些时间。
随后的测试看起来很快,因为一切都已经加载。

2.JIT编译

请记住,您的 .NET 程序集不包含 CPU 可以直接执行的代码。每当您调用任何 .NET 函数时,CLR 都会获取 MSIL 字节码并将其编译为可执行的机器代码,然后运行并运行该机器代码。它在每个功能的基础上执行此操作。
因此,如果您考虑到第一次调用任何函数时,它在 JIT 编译时会有一点延迟,这些东西可以加起来。如果您要调用大量函数或初始化大型第三方库(想想实体框架等),这可能会特别糟糕。
如上所述,后续测试看起来很快,因为许多函数已经被 JIT 编译并缓存在内存中。

那么,你怎么能绕过这个呢?

您可以通过减少程序集来缩短程序集加载时间。这意味着更少的文件搜索等等。microsoft .NET 性能指南更详细。另外,我相信将它们安装在全局程序集缓存中可能(??)会有所帮助,但我根本没有测试过,所以请多加注意。安装到 GAC 需要管理权限,并且是一项重量级的操作。您不想在开发期间这样做,因为它导致您出现问题(程序集从 GAC 加载而不是文件系统,因此您最终可能会在没有意识到的情况下加载代码的旧副本)。

您可以通过使用ngen预编译您的程序集来改进 JIT 时间。但是,与 GAC 一样,这需要管理权限并且需要一些时间,因此您也不希望在开发期间这样做。

我的建议?

首先,在单元测试中测量性能并不是一件特别好的或可靠的事情。谁知道 Visual Studio 在后台执行的其他操作可能会或可能不会影响您的测试。

一旦你得到你的代码,你就试图在一个独立的应用程序中进行基准测试,让它循环并运行所有测试两次,然后丢弃第一个结果:-)

于 2012-12-12T20:21:16.793 回答
0

“过早的优化是万恶之源。”

如果你以前没有测量过,你怎么知道你现在正在修理什么?你怎么知道你有一个需要解决的问题?

单元测试是为了操作正确性。它们可以用于性能,但我不会依赖它,因为许多其他因素会在运行时发挥作用。

您最好的选择是获得一个分析器(或使用 VS 附带的一个)并开始测量。

于 2012-12-12T19:53:28.350 回答