优化周:充满迷茫和冲击的一周

0 阅读10分钟

前言

大家好啊,这里是绣虎,这是第二周的总结,我的一周是从星期三开始的,也许是因为我的生日在星期三,那么我应该有一个新生,所以这个计划按照这个路线往前进行了。本周(4.8-4.15)的总结重点在于,我如何在自己的计划中加入各种决策,并完成了项目的深化,虽然只是简单的加工了一样玩具,但是也让我有不少困顿,我对此的感受,像是一个被困在漆黑房间的人,你知道真相离你很近,但四面八方来的风,让你不敢确信,你只能每一样都记在心里,直到摸索出那扇出去的门。

(一)Go语言的深度学习

一、slice的底层结构

在这一周,我学习了slice的底层结构,知道在go语言的底层中,它其实由一个指向底层数组的指针Data,一个长度Len,一个容量Cap组成。

  1. slice := make([]int, len, cap),这是它的定义代码,你可以清晰的看见它的底层结构。

  2. 何时扩容?这是一个值得讨论的问题,在那之前我会先来详细讲解底层结构中的具体组成。

    1. len:存储的元素的长度
    2. cap:底层数组的容量
    3. 只有当append(元素)&&len(slice)==cap(slice)时,才会触发扩容
  3. 扩容规则,这在Go1.18之后也有所改变:

    1. 当cap<1024时,newCap = cap*2
    2. 当cap>=1024时,newCap = cap*1.25,并且如果newCap< len,就会继续扩容,并且每次会在上一次的基础上多扩容0.25个原cap,直到newCap >= len
    3. 特殊规则:如果len一开始就为cap的2倍以上,直接就是newCap = cap*2
    4. 最后其实还有内容对齐,所以实际cap总是比长度值要大
  4. 扩容有什么影响吗?有的,而且影响还不小,所以我会在后面给出一个好的解决方案

    1. 扩容会创建新数组,并将旧数组里的内容拷贝过去,新切片指向新数组
    2. 扩容后地址改变,旧切片/旧引用依旧指向旧数组,不会影响
    3. 频繁扩容(如循环append不预分配)会影响性能
  5. 最佳实践

    1. 已知元素数量时,用make预分配cap:就如刚开始举的定义一样,其实slice有三种创建方法,但我只在此给读者展示其中一种,剩下用的少和用的最多的方法,还请读者自行探索
s := make([]int, 0, 1000)
  1. 不确定时,按初始小容量+动态append,避免一开始就分配过大

二、中间件

在学项目的时候,当我补充中间组件的代码时,学习的一些皮毛,在此分享给大家。

  1. 装饰器模式:我从这个设计模式来引入后面的内容,装饰器模式就是在不修改底层代码的前提给函数/对象“套一层”,增加新功能,本身没有变化,但是功能变多了。我们给出三个特征:
    1. 接收一个“原始处理器”
    2. 不修改原始处理器代码
    3. 返回一个“包装后的新处理器”,新增功能,并且可以套多层
  2. 而中间件最重要的就是装饰器模式,来理解中间件的底层原理(Go HTTP核心):
    1. 理解http.Handler和http.HandlerFunc接口:中间件本质就是[包装http.Handler的函数],遵循func(next http.Handler)http.Handler签名,利用装饰器模式扩展原有处理器的功能。
    2. 执行顺序:先注册的中间件先执行前置逻辑,后执行后置逻辑(如r.Use(Logger, Recovery),执行顺序:Logger 前置 → Recovery 前置 → 处理器 → Recovery 后置 → Logger 后置)。
  3. 中间件的最佳实践
    1. 单一职责:一个中间件只做一件事(如 Logger 只记录日志,不处理跨域);
    2. 可配置化:避免硬编码(如 CORS 允许的源通过配置文件 / 环境变量传入);
    3. 不篡改原始请求 / 响应:如需修改,使用http.ResponseWriter包装(如记录响应状态码需自定义ResponseWriter);
    4. 性能考量:高频中间件(如 Logger)尽量减少内存分配,避免影响接口响应速度。

(二)计算机基础的学习

一、计算机操作系统

凡聊计算机操作系统者,无不提及进程和线程,凡知go语言者,无不知Goroutine(协程)。

本周我就学习了进程和线程的定义,虽然早就知道,但是如此系统性,全面性地去学习,还属第一次。

  1. 进程:是程序的一次执行过程,是动态概念,是分配和管理资源的基本单位。每个进程有自己的地址空间。同时存在五个状态:初始态、执行态、等待态、就绪态和终止态。
  2. 线程:线程是cpu调度和分配的基本单位,同一进程内所有线程共享资源。一个进程可以拥有很多线程。
  3. 两者在资源分配上,进程是资源分配的基本单位,线程是任务调度和执行的基本单位。进程享有独立代码和数据空间,切换开销大,而线程共享空间内的资源,切换开销小。同时多个进程可以同时运行,一个进程内的多个线程也可以同时执行。系统为每个进程分配不同的内存空间,线程使用进程的资源。引入线程概念,实现代码并发执行,提高cpu利用率。且进程内包含多个线程和资源,崩溃时可以安全回收资源。
  4. 协程:用户级线程,更轻量。
  5. 同步机制:互斥锁、信号量。前者是保证资源的不泄露,后者是保证不阻塞,后者的实践可以参照上周我所做的生产者-消费者代码。

二、计算机网络

本周切入学习了HTTP/HTTPS的原理:HTTP/HTTPS是业务数据的语言规范,规范客户端与服务器之间超文本数据的请求与响应格式。它依赖下层传输层提供的通道,完成客户端与服务器的通信。

  1. 计算机通信原理:互联网通信遵循TCP/IP四层模型:

    1. 应用层:面向用户与业务,定义数据格式与业务语义,HTTP/HTTPS就在这一层工作
    2. 传输层:负责端到端的可靠传输,核心协议为TCP、UDP
    3. 网络层:负责IP寻址与路由转发,核心协议为IP
    4. 网络接口层:负责物理层的帧传输
    5. 安全层:TLS/SSL就相当于在这里,加密传输内容(HTTPS就是在不修改HTTP的基础上,加了一个安全层)
  2. HTTP核心设计:

    1. 核心模型: 在之前的Client-Server请求响应模型里我们尝试了,让TCP/IP来作为通道进行请求响应。我们可以知道永远是**客户端主动发起请求(问),服务器被动返回响应(答),服务器绝不会主动找你。**一次完整的HTTP通信=1次请求+1次响应,一一对应。
    2. 核心特性:无状态
      • 服务器不保存任何客户端的历史访问记录,每次请求都把你当新人。
      • 如果希望服务器记住:需要使用Cookie/Token,相当于每次请求都带有一个[身份证],能让服务器认出你。
    3. 报文结构无论是请求还是响应,都固定四个段落:
      1. 起始行:作用是要做什么/做了什么
        1. 请求行:方法 地址 HTTP版本
        2. 响应行:版本 状态码 描述
      2. 头部Headers:作用是附加说明(所有扩展功能都在这里)
        1. ETag:资源的唯一 “身份证”,用来做缓存校验;
        2. Expect:你对服务器的要求,服务器做不到就返回 417;
        3. Content-Type:内容的格式(比如 JSON、图片)。
      3. 空行:作用是告诉对方头部说完了,现在是正文。少了这个空行,服务器直接报400 Bad Request(看不懂、不能处理)。
      4. 正文Body:这里是要传的具体内容,GET 请求一般没有正文;POST/PUT 请求用来传表单、JSON 数据。
    4. 关键词:增删改查:查 GET、增 POST、改 PUT、删 DELETE
    5. 状态码:
      1. 200 OK:成功,服务器正常处理了
      2. 400 Bad Request:请求格式错了,服务器完全看不懂、不能处理,这是最核心的 “不能处理” 标记
      3. 404 Not Found:你要的资源不存在
      4. 417 Expectation Failed:满足不了Expect头的要求,不能处理
      5. 500 Internal Server Error:服务器自己崩了,处理不了
  3. HTTPS核心设计

    1. 本质:HTTPS=HTTP+TLS/SSL加密层,没有对HTTP做修改只是为内容加了一个加密壳
    2. 解决HTTP的缺陷
      1. 加密:HTTP传输的是明文,增加TLS/SSL加密层之后,便成为了密文
      2. 认证:用数字证书,证明你访问的是真网站,不是骗子冒充的
      3. 完整性:内容被篡改就能立刻发现,防止数据被修改
    3. 加密逻辑:用非对称加密+对称加密的混合方案,兼顾安全和速度:
      1. 非对称加密(慢、极安全):只用来握手阶段,商量好一个只有咱俩知道的临时加密暗号(会话密钥);
      2. 对称加密(快、性能好):商量好暗号后,所有 HTTP 内容都用这个暗号加密传输
      3. 信任根基:数字证书(权威 CA 机构给网站发的 “身份证”),防止骗子换掉暗号、冒充网站。
  4. 版本演替

    1. HTTP/1.0:一次请求开一次 TCP 连接,极慢,已淘汰
    2. HTTP/1.1:当前主流版本,一个 TCP 连接可以传多次请求,默认开启
    3. HTTP/2:多路复用,一个连接同时传多个请求,不用排队,更快
    4. HTTP/3:基于 UDP+QUIC 协议,弱网环境也很快,正在快速普及

(三)一个简易的Go_Web项目的搭建:CRUD功能的基础搭建

一个非常基础的代码,我在这一周用这份代码疏通了一个标准的Go_Web项目的搭建,从存储层、服务层、业务逻辑层、接口层、config和main主文件口,逐层搭建,并同步学习其知识体系。最后还对测试进行了浅层的了解。

(四)建立了错题本的算法世界

算法一直是我的难关,对于这么一个双非的笨学生来说,理解算法的底层意义,这对我来说是个问题。所以我加入了错题本。

在本周我学习了链表的哑节点,一种可以减少错误处理的优雅方式;还有链表的双指针、删除、复制、合并等,我会在之后按照3、7、14、30的方式去复习它们,同时加入一些算法课程,通过理解原理,去继续深入了解他们。

结尾

第二周,为什么说迷茫呢,虽然体系化了,但是仍然很困难的进行着。我在下一周,会开始辅助算法的学习,我会全面而又细致地去琢磨计算机基础,也许不一定吃的很多,但一定会吃的很细致。还有一点最最最重要的,我会早睡早起,宁可睡一好觉,不做低效磨洋工。晚安,明天见,这个世界没有那么简单,我不知道是否一定能美好的醒来。但无论如何,和你说声“你好!世界!我来了!!!”。