分类:蟠木朽株

共 21 篇文章
Go map:从 hmap 到 Swiss Table
Go map:从 hmap 到 Swiss Table

Go 的 map 太常用了,以至于很多人不再把它当作数据结构。写一行 m[key],编译器和 runtime 就替我们完成了哈希、探测、比较、扩容和内存管理。代码很短,代价却不短。更麻烦的是,网上关于 Go map 的文章经常混着两个时代:Go 1.23 及以前的 hmap、bucket、overflow bucket;Go 1.24 起默认启用的 Swiss Table、group、control word、table 和目录。两套实现都服务于同一个语言语义,但底层路线已经

2025-02-16•约 4.4 千字
译:简单性
译:简单性

在 2009 年 5 月,Google 举办了一场内部的「设计巫术(Design Wizardry)」小组讨论会,演讲者有我和 Jeff Dean、Mike Burrows、Paul Haahr、Alfred Spector、Bill Coughran。以下是略加编辑的我的演讲记录。尽管一些细节已经过时,但在今时今日,核心主旨可能比那时候更显重要。简单胜于复杂越简单的东西就越容易理解,也就更容易构建、调试和维护。容易理解是最重要的,无法理解就无法进行其他任何后续步骤。看看 g

2024-10-01•约 2.2 千字
HTTP/3 与 QUIC:换掉 TCP 之后,网络真的更快了吗?
HTTP/3 与 QUIC:换掉 TCP 之后,网络真的更快了吗?

HTTP/3 最容易被说成一句话:「HTTP 改用 UDP,所以更快。」这句话不能说完全错,毕竟 HTTP/3 的确运行在基于 UDP 的 QUIC 之上;可它省略的部分,恰好比留下来的更多。UDP 没有可靠传输、拥塞控制、连接状态和加密。倘若只把 TCP 删掉,再把 HTTP 报文扔进 UDP 数据报,得到的不会是下一代 Web,而是一台更快丢数据的机器。真正承担工作的,是 QUIC。它在用户空间重新提供可靠传输、流量控制、拥塞控制、丢包恢复和连接管理,把 TLS 1.3

2024-05-01•约 5.4 千字
Go 的 Goroutine 与协程
Go 的 Goroutine 与协程

很多文章把协程解释成「比线程轻的东西」,把 async/await 解释成「暂停一下再继续」,再把 go func() 解释成「启动一个异步任务」。这些说法不能算错,但它们没有回答最关键的问题:到底保存了什么上下文,谁负责保存,谁决定什么时候恢复?如果不回答这个问题,进程、线程、协程、goroutine、异步函数就会变成一串互相替换的术语。更麻烦的是,go func() 和 await 看起来都像是在控制执行权,却其实做着完全不同的事情。本文的主线只有一句话:go func(

2024-02-04•约 5.5 千字
简述 TCP/IP:从一个数据包说起
简述 TCP/IP:从一个数据包说起

打开浏览器,输入一个网址,页面很快出现在眼前。这件事熟悉得近乎无聊,但若继续追问,问题马上就多了起来:电脑怎么知道服务器在哪?数据为什么没有走错门?跨过 Wi-Fi、光猫、运营商和海底光缆之后,对方又如何确认内容没有缺斤少两?很多回答会祭出一张 OSI 七层模型图,再从物理层一路背到应用层。图当然没错,只是背完之后,人仍然可能解释不了一个更实在的问题:当网络会丢包、乱序、重复、限速甚至中断时,TCP/IP 到底替应用做了什么,又故意没做什么?先给出一个不太严谨但好用的答案:I

2022-04-01•约 7.8 千字
程序是怎么运行的
程序是怎么运行的

程序是怎么运行的?这个问题听上去像是计算机组成原理课的第一道题,答案通常也很像课本:编译器把源代码翻译成机器码,操作系统把程序加载到内存,CPU 执行它。没错,但这句话把最有意思的部分全部压扁了。操作系统为什么能同时运行浏览器、音乐播放器和终端?CPU 明明一次只能执行一条指令,所谓「同时」是怎么来的?一个普通程序为什么不能随便读取别的程序的内存?printf 最后又是怎么把字符送到屏幕上的?当我们在终端输入 ./hello 时,操作系统究竟做了什么?说到底,计算机并没有我们

2022-02-04•约 10.4 千字