读程序员的制胜技笔记08_死磕优化(上)

news2024/11/25 10:27:07

1. 过早的优化是万恶之源

1.1. 著名的计算机科学家高德纳(Donald Knuth)的一句名言

1.2. 原话是:“对于约97%的微小优化点,我们应该忽略它们:过早的优化是万恶之源。而对于剩下的关键的3%,我们则不能放弃优化的机会。”

2. 过早优化是提升自己的根源

2.1. 优化就是解决问题,过早优化创造了暂时没有发现的、假想的问题来解决,就像国际象棋选手设置棋局来挑战自己

2.2. 探索性编程是提高技能的合法途径

3. 不要过早优化的原因

3.1. 优化会增加代码的耦合性,使其更难维护

3.2. 优化也是一项投资,其回报在很大程度上取决于你能将优化结果保持多久

3.3. 如果规范发生变化,你所进行的优化可能会让你陷入一个难以摆脱的困境

3.4. 你可能试图为一个本来就不存在的问题进行优化,而使你的代码变得不那么可靠

4. 解决该解决的问题

4.1. 你需要真正理解你在优化时到底做了什么权衡,这意味着你必须把需要解决的问题了解透彻

4.2. 根据问题的性质,解决方式可以发挥的效用和实现它需要花费的时间可能有很大的不同

4.3. 基准测试(benchmarking)

4.3.1. 比较性能指标的行为

4.3.1.1. 只能给你一堆用于比较的数字
4.3.1.2. 不能告诉你代码的运行速度是快还是慢
4.3.1.3. 可以告诉你它们比其他一些代码运行得慢还是快

4.3.2. 无法帮助你确定造成性能问题的根本原因

4.3.3. 可以帮助你确定是否存在性能问题

4.3.4. 你应该常常对你的那些代码优化进行基准测试,来看看你的优化是否还有更进一步的余地

4.3.5. BenchmarkDotNet库

4.3.5.1. 可以消除因测量误差或者调用开销产生的波动
4.3.5.2. 适用于微观基准测试
4.3.5.2.1. 适用于微观基准测试
4.3.5.3. 基准测试并没有试图消除函数调用的开销或for循环本身的开销

4.3.6. Math.DivRem()函数比普通的除法和求余操作能快多少

4.3.6.1. C#
public class SampleBenchmarkSuite {
  [Params(1000)]  ⇽--- 避免编译器优化
  public int A;
  [Params(35)]  ⇽--- 
  public int B;
  [Benchmark]  ⇽--- 用属性标记要进行基准测试的操作
  public int Manual() {
    int division = A / B;
    int remainder = A % B;
    return division + remainder;  ⇽--- 我们将值返回,这样编译器就不会丢掉计算步骤
  }
  [Benchmark]  ⇽--- 
  public int DivRem() {
    int division = Math.DivRem(A, B, out int remainder);
    return division + remainder;  ⇽--- 
  }
}
using System;
using System.Diagnostics;
using BenchmarkDotNet.Running;
namespace SimpleBenchmarkRunner {
  public class Program {
    public static void Main(string[] args) {
      BenchmarkRunner.Run<SampleBenchmarkSuite>();
    }
  }
}
4.3.6.2. Math.DivRem()的速度是分别进行除法和求余操作的两倍
4.3.6.3. 使用Stopwatch编写自己的基准测试程序
4.3.6.4. C#
private const int iterations = 1_000_000_000;
private static void runBenchmarks() {
  var suite = new SampleBenchmarkSuite {
    A = 1000,
    B = 35
  };
  long manualTime = runBenchmark(() => suite.Manual());
  long divRemTime = runBenchmark(() => suite.DivRem());
    reportResult("Manual", manualTime);
    reportResult("DivRem", divRemTime);
  }
private static long runBenchmark(Func<int> action) {
  var watch = Stopwatch.StartNew();
  for (int n = 0; n < iterations; n++) {
    action();  ⇽--- 我们在这里调用基准测试代码
  }
  watch.Stop();
  return watch.ElapsedMilliseconds;
}
private static void reportResult(string name, long milliseconds) {
  double nanoseconds = milliseconds * 1_000_000;
  Console.WriteLine("{0} = {1}ns / operation",
    name,
    nanoseconds / iterations);
}
4.3.6.5. DivRem函数的运行速度比除法和求余操作快,因为它被转换为需要更少周期的指令

4.4. 性能与响应性

4.4.1. 关于缓慢的一般原则

4.4.1.1. 任何需要超过100毫秒的动作都会让人感觉到延迟,而任何需要超过300毫秒的动作都被认为是缓慢的,更不要说花整整1秒的动作

4.4.2. 性能并不总是与响应性(responsiveness)有关

4.4.3. 任务是计算密集型(computationally intensive)的

4.4.3.1. 最快的计算方法是在工作完成之前不做其他事情
4.4.3.2. 与其以最快的速度进行计算,不如腾出一些计算周期来显示一个进度条,也许可以计算出估计的剩余时间,并在用户等待的时候显示一个漂亮的动画
4.4.3.3. 最后,你的代码运行速度会变慢,但结果会更成功

4.4.4. 延迟也会影响性能,而不仅仅是用户体验

4.4.4.1. 你的数据库驻留在磁盘上,而你的数据库服务器驻留在网络上,这意味着,即使你写了最快的SQL查询,并在你的数据库上定义了最快的索引,你仍然受到物理定律的约束,你不能得到任何快于1毫秒的结果

5. 迟缓的剖析

5.1. 并不是所有的性能问题都是关于速度的

5.1.1. 有些是关于响应性的

5.2. CPU是处理从RAM中读取的指令的芯片,并在一个永无止境的循环中重复执行这些指令

5.3. 时钟周期(clock cycle)

5.3.1. 简称为周期

5.4. CPU速度通常以赫兹(Hz)为单位,表示它在1秒内能处理多少个时钟周期

5.5. 有时CPU甚至可以处理比其处理速度所允许的更多指令

5.5.1. 一些指令需要一个以上的时钟周期来完成

5.5.2. 现代CPU可以在一个核心上并行处理多条指令

5.6. 每一个与代码执行速度有关的性能问题都归结为有多少条指令被执行和被执行多少次

5.7. 当你优化代码时,本质上你要做的是减少指令的执行次数,或者使用更快版本的指令

6. 从头开始

6.1. 直接在源头解决问题

6.1.1. 定位到根本问题

6.2. 减少执行指令数量第二好的方法是选择一个更快的算法

6.3. 最好的方法显然是完全删除代码

6.3.1. 删除你不需要的代码

6.3.2. 不要在代码库中保留不需要的代码

6.3.2.1. 即使不会直接降低代码的性能,也会降低开发人员的“性能”,最终降低代码的性能

6.3.3. 不要保留注释过的代码

6.3.3.1. 可以使用你最喜欢的源代码控制系统(如Git或Mercurial)的历史功能来恢复旧代码

6.4. 让代码运行速度变慢的最简单的方法之一是把它放在另一个循环里

6.4.1. 不应该把计算密集型的代码放在属性的源代码里面

6.4.2. 小心属性

6.4.2.1. 它们包含逻辑,而它们的逻辑并不简单

6.5. 面向字符串的编程

6.5.1. 选择适合的类型会比使用字符串拥有更好的性能

6.5.2. 字符串有一些微妙的方式可以被添加进你的代码里

6.5.3. 一个布尔变量来优化代码

6.5.3.1. C#
if ((string)HttpContext.Items["Bozo"] == "true") {
...
}
6.5.3.2. C#
if ((bool?)HttpContext.Items["Bozo"] == true) {
...
}
6.5.3.3. 节省存储开销和解析开销,还有助于避免你的打字错误,比如把True打成ture
6.5.3.4. 简单的错误对你来说影响不是特别大,但如果错误变成了习惯,影响就会积小成大

6.6. if语句中的布尔表达式是按照它们的书写顺序来评估

6.6.1. 可以简单地调换表达式的位置

6.6.2. 建议根据操作数类型对表达式进行排序

6.6.2.1. 1.变量
6.6.2.2. 2.字段
6.6.2.3. 3.属性
6.6.2.4. 4.方法调用

6.6.3. 逻辑符号是有优先级之说的,以确保你在优化布尔运算时不会意外地破坏if语句中的逻辑

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1191178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

12 # 手写 findIndex 方法

findIndex 的使用 findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1。 <script>var arr [1, 3, 5, 7, 8];var result arr.findIndex(function (ele, index, array) {console.log("ele----->", ele);conso…

【Java】SPI在Java中的实现与应用

一、SPI的概念 1.1、什么是API&#xff1f; API在我们日常开发工作中是比较直观可以看到的&#xff0c;比如在 Spring 项目中&#xff0c;我们通常习惯在写 service 层代码前&#xff0c;添加一个接口层&#xff0c;对于 service 的调用一般也都是基于接口操作&#xff0c;通…

已解决:rm: 无法删除“/opt/module/zookeeper-3.4.10/zkData/zookeeper_server.pid“: 权限不够

解决&#xff1a; ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Stopping zookeeper ... /opt/module/zookeeper-3.4.10/bin/zkServer.sh: 第 182 行:kill: (4149) - 不允许的操作 rm: 无法删除"/opt/module/zooke…

开发知识点-Python

Python从小白到入土 python渗透测试安全工具开发锦集Python安全工具编程基础第一章 Python在网络安全中的应用第一节 Python黑客领域的现状第二节 我们可以用Python做什么第三节 第一章课程内容总结 第二章 python安全应用编程入门第一节 Python正则表达式第二节 Python Web编程…

C++二分查找算法:阶乘函数后 K 个零

涉及知识点 二分查找 数学 题目 f(x) 是 x! 末尾是 0 的数量。回想一下 x! 1 * 2 * 3 * … * x&#xff0c;且 0! 1 。 例如&#xff0c; f(3) 0 &#xff0c;因为 3! 6 的末尾没有 0 &#xff1b;而 f(11) 2 &#xff0c;因为 11! 39916800 末端有 2 个 0 。 给定 k&a…

Python--列表及其应用场景

1.为什么需要列表 思考&#xff1a;有一个人的姓名(laowang)怎么书写存储程序&#xff1f; 用 变量。如&#xff1a;name laowang 但是&#xff0c;如果要记录很多人的名字&#xff0c;怎么办&#xff1f; 思考&#xff1a; 如果一个班级100位学生&#xff0c;每个人的…

17 Linux 中断

一、Linux 中断简介 1. Linux 中断 API 函数 ① 中断号 每个中断都有一个中断号&#xff0c;通过中断号可以区分出不同的中断。在 Linux 内核中使用一个 int 变量表示中断号。 ② request_irq 函数 在 Linux 中想要使用某个中断是需要申请的&#xff0c;request_irq 函数就是…

【Unity ShaderGraph】| 如何快速制作一个炫酷的 全息投影效果

前言 【Unity ShaderGraph】| 如何快速制作一个炫酷的 全息投影效果一、效果展示二、 全息投影效果 前言 本文将使用ShaderGraph制作一个 炫酷的 全息投影效果 &#xff0c;可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章&#xff1a;【Unity Shader…

mac 卸载第三方输入法

输入法设置里的移除&#xff0c;并不是真的卸载&#xff0c;点击还是能添加回来 在活动监视器里强制退出此输入法在访达界面使用快捷键 ShiftcommandG在弹出的对话框内输入以下路径&#xff08;/资源库/Input Methods&#xff09;&#xff0c;再点击下面的前往找到你要卸载的输…

HadSky+内网穿透打造个人专属社区论坛并远程访问

文章目录 前言1. 网站搭建1.1 网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09;2.4 公网访问测试 总结 前言 经过多年的基础…

盘点那些开发中经常用到的git命令

入职第一天 配置邮箱账号 git config —global user.email "XXXX" git config —global user.name "XXXX" 生成公钥 ssh-keygen -t rsa -C "你的邮箱"生成的文件默认在c盘:/用户/当前用户/.ssh文件夹下&#xff0c;也可以指定文件 打开git网页&…

MySQL(12):MySQL数据类型

MySQL中的数据类型 常见数据类型的属性&#xff1a; 整数类型 整数类型一共有 5 种&#xff0c;包括 TINYINT、SMALLINT、MEDIUMINT、INT&#xff08;INTEGER&#xff09;和 BIGINT。 CREATE TABLE test_int1 ( X TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT );…

Postgresql数据类型-时间类型

PostgreSQL对时间、日期数据类型的支持丰富而灵活&#xff0c;本节介绍PostgreSQL支持的时间、日期类型&#xff0c;及其操作符和常用函数。 PostgreSQL支持的时间、日期类型如表所示。 我们通过一个简单的例子理解这几个时间、日期数据类型&#xff0c;先来看看系统自带的now…

高性能网络编程 - 解读5种I/O模型

文章目录 服务端处理网络请求流程图基础概念阻塞调用 vs 非阻塞调用同步处理 vs 异步处理阻塞、非阻塞 和 同步、异步的区别recvfrom 函数 五种I/O模型I/O模型1&#xff1a;阻塞式 I/O 模型(blocking I/O&#xff09;I/O模型2&#xff1a;非阻塞式 I/O 模型(non-blocking I/O&a…

实用技巧:嵌入式人员使用http服务模拟工具模拟http服务器测试客户端get和post请求

文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134305752 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

卡尔曼滤波EKF

目录 一、概述 二、卡尔曼滤波的5个公式 三、应用案例&#xff1a;汽车运动 四、应用案例&#xff1a;温度估计 五、总结 一、概述 初学者对于卡尔曼滤波5个公式有点懵&#xff0c;本文先接地气地介绍5个公式&#xff0c;然后举两个常用例子加强理解&#xff0c;同时附有M…

杰里6969系列控制RGB彩灯模式

1、任务目标 实现可以接收到APP传输过来的数据&#xff0c;可以通过传输的数据前几个字节识别到所需要控制的模式&#xff0c;然后提取数据的后几个字节来分别对RGB灯进行不同的的PWM波控制&#xff0c;从而实现跳变和渐变的效果。 2.跳变&#xff08;分布调试记录&#xff09…

创建多层级行索引,创建多层级行索引的DataFrameMultiIndex.from_product()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 创建多层级行索引, 创建多层级行索引的DataFrame MultiIndex.from_product() [太阳]选择题 使用pd.MultiIndex.from_product()&#xff0c;下列输出正确的是&#xff1a; import pandas as pd…

一键批量删除文件名中的空格,高效整理您的文件

你是否曾经因为文件名中多余的空格而烦恼&#xff1f;这些空格不仅影响了文件的美观&#xff0c;还可能导致一些不必要的错误。现在&#xff0c;我们向您介绍一款全新的工具&#xff0c;它可以帮助您一键批量删除文件名中的空格&#xff0c;让您的文件整理更加轻松、高效&#…

一款功能强大的web目录扫描器专业版

dirpro 简介 dirpro 是一款由 python 编写的目录扫描器&#xff0c;操作简单&#xff0c;功能强大&#xff0c;高度自动化。 自动根据返回状态码和返回长度&#xff0c;对扫描结果进行二次整理和判断&#xff0c;准确性非常高。 已实现功能 可自定义扫描线程 导入url文件进…