【问题标题】:What are some resources I can use to learn profiling/optimizing?我可以使用哪些资源来学习分析/优化?
【发布时间】:2010-10-07 16:46:04
【问题描述】:

我刚刚继承了一个运行速度很慢的 C# 项目,必须开始对其进行优化。我首先想做的是了解更多关于分析/优化的知识,因为我以前不必这样做。所以问题是我从哪里开始,我可以阅读哪些书籍/博客/文章?

我确实知道 ANTS 分析器等 .net 分析器,但我不知道如何有效地使用它们。我并没有真正使用过它,只是让它在几个示例应用程序上运行以玩弄输出。

【问题讨论】:

标签: c# .net optimization profiling


【解决方案1】:

优化代码有两个步骤。

首先,您需要找出慢的原因。这就是分析,正如您可能猜到的,分析器通常用于此目的。大多数分析器通常易于使用。您通过分析器运行您的应用程序,当它终止时,分析器将显示在每个函数中花费了多少时间,独占(此函数不计算从该函数调用的函数中花费的时间)以及包含(在此中花费的时间)函数,包括子函数调用)。

换句话说,你得到一个很大的调用树,你只需要寻找大数字。通常,很少有函数消耗超过 10% 的执行时间。所以找到这些,你就知道要优化什么了。

请注意,分析器既不是必需的,也不一定是最佳方法。一个非常简单但有效的方法是在调试器中运行程序,并在几个准随机时间暂停执行并查看调用堆栈。只做几次,你就会非常清楚你的执行时间花在了哪里。在此答案下发表评论的@Mike Dunlavey 在其他地方深入描述了这种方法。

但既然您知道执行时间花在哪里了,那么棘手的部分就来了,如何优化代码。

当然,最有效的方法通常是高级方法。问题一定要这样解决吗?它必须解决吗?是否可以提前解决并缓存结果,以便在应用程序的其余部分需要时立即交付? 有没有更有效的算法来解决这个问题?

如果您可以应用此类高级优化,请执行此操作,看看是否充分提高了性能,如果没有,请再次分析。

迟早,您可能需要深入研究更底层的优化。不过,这是一个棘手的领域。今天的计算机非常复杂,您从中获得的性能并不简单。分支或函数调用的成本可能因上下文而异。将两个数字加在一起可能需要 0 到 100 个时钟周期,具体取决于这两个值是否已经在 CPU 的寄存器中、当时正在执行的 else 以及许多其他因素。因此,此级别的优化需要 (1) 充分了解 CPU 的工作原理,以及 (2) 大量的实验和测量。您可以轻松地做出您认为会更快的更改,但您需要确定,因此请测量更改前后的性能。

有一些一般的经验法则通常可以帮助指导优化:

I/O 很昂贵。 CPU 指令以几分之一纳秒为单位进行测量。 RAM 访问大约为几十到几百纳秒。访问硬盘驱动器可能需要数十毫秒秒。很多时候,I/O 会拖慢你的应用程序。 您的应用程序是执行少量大型 I/O 读取(在一个大块中读取 20MB 文件)还是无数小型读取(从一个文件读取字节 2,052 到 2073,然后从另一个文件读取几个字节)?更少的大型读取可以将您的 I/O 速度提高数千倍。

页面错误也涉及硬盘访问。内存中的页面必须被推送到页面文件,而分页的页面必须被读回内存。如果这种情况经常发生,它会很慢。您能否改善数据的局部性,从而减少同时需要的页面?您是否可以简单地为主机购买更多 RAM 以避免不得不分页数据? (作为一般规则,硬件很便宜。升级计算机是一个完全有效的优化 - 但要确保升级会有所作为。购买更快的计算机不会加快磁盘读取速度。如果一切都适合 RAM在您的旧系统上,购买内存是 8 倍的没有意义)

您的数据库也依赖于硬盘访问。那么,您可以在 RAM 中缓存更多数据,并且只是偶尔将其写入数据库吗? (当然有风险。如果应用程序崩溃了怎么办?

然后是每个人都喜欢的线程。现代 CPU 有 2 到 16 个 CPU 内核可用。你都在用吗?你会从使用它们中受益吗?是否有可以异步执行的长时间运行的操作?应用程序在单独的线程中启动操作,然后能够立即恢复正常操作,而不是阻塞直到操作完成。

所以基本上,使用分析器来了解您的应用程序。它如何花费它的执行时间,它在哪里花费?内存消耗有问题吗?什么是 I/O 模式(硬盘和网络访问,以及任何其他类型的 I/O)? CPU 是一直在不停地运转,还是空闲等待一些外部事件,例如 I/O 或计时器?

然后尽可能多地了解运行它的计算机。了解它有哪些可用资源(CPU 缓存、多核),以及它们各自对性能的意义。

这一切都非常模糊,因为优化大型数据库服务器的技巧将非常不同于优化一些大型数字运算算法。

【讨论】:

  • @jalf:这是对性能分析作为大主题的一个很好的总结。我喜欢把它想象成一个小主题。对调用堆栈进行采样(我手动进行)可以快速准确地了解浪费的位置。
【解决方案2】:

我正在上一门本科课程(一个主题是性能分析),推荐的文本是The Art of Computer Systems Performance Analysis: Techniques for Experimental Design, Measurement, Simulation, and Modeling。这是关于这个主题的圣经,可能有点矫枉过正。

【讨论】:

  • 矫枉过正非常适合那些不眠之夜,您只需阅读一些关于性能分析的枯燥文本即可让您永远出局:) thx
【解决方案3】:

如果您熟悉并已经购买了 ANTS(一款非常出色的分析器),请转至 here 获取快速教程以帮助您启动和运行。

【讨论】:

    【解决方案4】:

    如果你有 Visual Studio Team System,我建议使用它包含的 Profiler。
    它在“分析->分析器”下
    使用这个分析器非常简单。你可以潜入其中,看看你是怎么做的。动手实践比您将要阅读的任何文章或书籍都要好。

    只需单击几下,即可轻松找到前几个瓶颈。解决它们可能有点棘手,但同样,优化代码只是一个问题或实践和经验。

    【讨论】:

      【解决方案5】:

      阅读Rico Mariani's blog。在升职之前,他是 .Net 的主要性能调整人员。他博客中较早的条目有很多很好的建议。我会从头开始,朝着你的方向努力。

      加上您已经找到的文章(尤其是first one)应该可以帮助您入门。

      【讨论】:

        【解决方案6】:

        有分析器和性能分析工具,但是当您尝试查找/购买/安装/学习一个时,只需尝试老前辈的技巧...

        在 IDE 下运行应用程序,当它运行缓慢时,点击“暂停”按钮,询问它在做什么,以及为什么。回答这个问题的最佳方法是阅读调用堆栈。

        如果它比应有的速度慢几倍,比如 10 倍,这意味着它花费了 90% 的时间在做一些不必要的事情,这就是你会发现它在做的概率 .如果您重复多次,您可以尽可能准确地确认您的怀疑。

        所以你不需要昂贵/流行但模糊的放大镜。

        所以找到慢的原因并不是难事,通常有几个。

        困难的部分是,在你修复了一些“低垂的果实”之后,你可能不得不面对这样一个事实,即导致缓慢的主要原因是过度设计。

        祝你好运。

        【讨论】:

          【解决方案7】:

          我以前使用过分析器,它们可能会有所帮助,但是您可以通过创建一个单例秒表类型类并“单击”它来获得很多帮助(让它打印出自上次单击以来的时间以及发生了什么刚刚完成,花了那段时间)在您认为可能有问题的方法之前和之后。

          如果速度是整个应用程序的问题,您可能无法对此做太多事情,但您可能可以进行一些更改...

          寻找内循环。这些都是性能死亡。内部循环可能是由一些简单的事情引起的,比如对链表进行索引,或者对基于数组的列表进行插入排序。 (曾经有一个列表框需要 10 到 20 分钟才能填充数万个条目,虽然条目太多,但最糟糕的是它通过将每个条目插入到数组列表中来对其进行排序)。

          查找您基于按键进行长时间操作的情况。这些几乎都应该在主线程之外完成。

          甚至不要考虑优化类的数量或实例化的频率、字符串连接(循环之外)、清空变量或任何其他看起来应该有帮助的愚蠢策略。我尝试了一些,但当我真正放慢速度时总是觉得很傻,因为我没有运行时那么聪明。

          【讨论】:

            【解决方案8】:

            我会下载一些可用的分析工具(免费试用)并开始使用它们。

            我用过jetbrains,还有其他的。 (ants for exampledevpartnera MS one?atomatedqa 等)运行它们应该不会有太多问题。他们的报告可为您提供大量信息,您只需使用应用程序即可快速学习。

            其中任何一个都可能对您有所帮助,并且使用试用版非常好。然后,您可以搁置购买该工具的决定,或者购买最有用/最容易使用的工具。一般来说,它们可以节省大量时间并且物有所值,尽管有些可能很昂贵。 (当有非常好的工具可以花更少的钱时,我很难与高端的人相处)

            在安装和运行它们的第一天,您可能会发现一些严重/主要的性能问题。我知道我做到了。

            祝你好运。

            只需下载一些工具并开始运行您的应用程序。

            编辑:

            至于书籍和学习 - 基本上了解代码问题的最佳方法是找到错误代码。多次与经验丰富的开发人员进行检查会很有帮助。

            举个例子:我认为乔尔早前曾写过一篇关于他做过类似事情的文章

            for (int i = 0; i

            很明显,您将在循环的每次迭代中调用 strlen(昂贵)。

            在分析器告诉您时间花费在哪里之后,您必须查看一些代码,看看代码是否可以通过简单的事情轻松修复,或者必须在设计中进行更改算法。

            【讨论】:

              【解决方案9】:

              【讨论】:

                【解决方案10】:

                这对 C# 帮助不大,但 OS X Shark 工具(随 Apple 开发人员工具提供)是我遇到的最好的分析工具。使用起来几乎很有趣!

                关于分析,有两种方法。首先,您应该了解该软件。尤其是数据结构。除非您先了解它,否则不要开始优化。

                其次,你应该测量(这似乎你将要做的)。我几乎总是被我的直觉误导。我认为次要的地方是耗时的。这也意味着当您进行优化时,您总是针对您运行的特定测试用例集进行优化。这种情况的选择很重要。

                【讨论】:

                  【解决方案11】:

                  您已经用 Profiler 击中了要害。所有这些,至少我使用过的所有,都遵循相同的基本方法。您选择可执行文件,然后运行应用程序。

                  你对输出所做的就是找到花费最多时间的方法。l 这还不是全部,但你要求一个学习如何优化代码的好方法,所以长时间运行的例程是一个很好的起点.您提到的 ANTS 将默认显示长时间运行的例程,大多数(如果不是全部)其他例程也是如此。

                  你可以排除容器方法,比如 Main(),除非你有很多代码(不太可能)。

                  总的来说,我发现三个方面的浪费最多:

                  1. 循环
                  2. 递归
                  3. 网络延迟

                  如果您还要分析您的数据库,则数据库的区域 #3 通常很容易发现,因为您会看到点击次数。减少网络延迟的最佳方法,无论是否是数据库(例如服务调用),都是通过消息而不是 CRUD 进行通信。不要查询每个表,一次一个。不幸的是,该解决方案通常需要封装许多常见数据层的一部分。

                  递归和循环是非常相似的问题。如果您想物有所值,请先点击内部循环。

                  在 .NET 中,您还可以通过学习基本 IL 并通过 Reflector 等工具检查应用程序的 IL 来了解很多关于优化的知识。有点浪费时间,如果这不是你的工作描述的主要部分,或者你可能想要在未来的职业生涯中做的事情。作为一名消防员的薪水很高,但作为一名只做维护的编码员可能会很无聊。

                  关于优化和分析 .NET 应用程序的书籍只有几本。在标题中进行了优化的那个。 .NET 的调试书有一些关于 Profiling 的信息,但不是很深。这是一本非常适合阅读的优化书籍,因为许多导致错误的问题也会出现在您的优化之旅中。

                  【讨论】:

                    猜你喜欢
                    • 2013-09-29
                    • 1970-01-01
                    • 2019-08-31
                    • 1970-01-01
                    • 2013-04-24
                    • 2010-09-20
                    • 2011-10-02
                    • 1970-01-01
                    相关资源
                    最近更新 更多