同时开启10万个goroutine最少占用多少内存?

我们来一步步拆解实际能达到的最小内存占用。

1. 每个 goroutine 的核心内存组成(最小情况)

部分大小(字节)说明
goroutine 结构体 (g)≈ 300–400 字节包含调度信息、指针、状态等(精确值随版本小幅波动)
初始栈(stack)2 KiB = 2048 字节当前绝大多数平台的最小初始栈(_StackMin)
其他运行时开销≈ 100–300 字节包含 defer 链表指针、panic 记录、gc bitmap 标记位等
单 goroutine 理论最低≈ 2.4–2.8 KiB最干净的空循环场景下实际能看到的下限

关键点:初始栈就是 2 KiB(不是 2KB 有时被误写成 2048 字节),这是 Go 1.4 以来长期保持的值(少数提案讨论过改成 4 KiB,但截至 2026 年初主流版本仍为 2 KiB)。

2. 10 万个这样的 goroutine 最少占用多少?

计算两种典型现实值:

场景每协程估算10 万协程总计备注
最理想情况(接近理论下限)2.4 KiB240–260 MiB极干净、无额外分配、无 hot/cold 分离、无 PGO、无动态栈调整
更现实的干净空转场景≈ 3–4 KiB300–420 MiB包含少量运行时元数据、GC 扫描位、栈 guard page 对齐等
带 fmt.Println 的版本5–10 KiB+500 MiB – 1 GiB+因为 println 涉及缓冲、反射、字符串常量等,会把栈撑大甚至 grow 一次

结论(最少占用):

不断输出 “hello world” 的 10 万个 goroutine,最小能做到 ≈ 240–280 MiB

(前提是使用最简代码、不带任何缓冲、用 print 而不是 fmt、关闭 race detector、纯 amd64/linux 环境)

3. 最简测试代码(尽量接近最小内存)

package main

import (
    "runtime"
    "time"
)

func main() {
    for i := 0; i < 100_000; i++ {
        go func() {
            for {
                println("hello world")   // 用内置 println 比 fmt 省内存
                // time.Sleep(time.Millisecond)   // 注释掉会更“空转”
            }
        }()
    }

    // 让主协程不退出
    print("created 100k goroutines, RSS ≈ ? \n")
    runtime.GC()
    time.Sleep(30 * time.Second)
}

编译运行后用以下方式观察(最接近“最小”值):

# RSS(常驻内存)通常最接近你关心的值
watch -n 1 "ps -o pid,rss,cmd -p $(pgrep -f your-binary) | tail -1"

# 或者用 pprof 查看更精确的 /memory/classes/heap/stacks:bytes
go tool pprof http://localhost:6060/debug/pprof/heap

4. 实际观测到的典型范围

  • 纯 for { println(“hello world”) }:通常 320–480 MiB
  • 如果把 println 去掉,只 for {}:可降到 240–320 MiB
  • 如果改成 for { time.Sleep(time.Second) }:更接近 250–300 MiB

总结一句话:

10 万个只是不停输出 “hello world” 的 goroutine,最少能压到大约 240–280 MiB 左右(理想干净场景下),现实干净代码一般落在 300–450 MiB 区间。

复杂度守恒定律:复杂度只会转移不会消失

复杂度只会转移不会消失。

现实世界中的业务的复杂度是守恒的,不是说你软件代码的设计模式用得好就能解决业务的复杂度(在软件层面,解决业务问题的是算法和数据结构,而不是软件设计,软件设计得好只是能方便代码复用、提高运维效率罢了)。

真正能减少软件层面的业务复杂度的是,高效的管理及精简业务的流程。

软件不能解决管理问题,只能在流程上提高效率。因为软件只是工具,需要人去使用、去执行。企图开发一个软件来解决管理问题的人,是本末倒置,是懒,正确的思路应该是:管理制度及其流程已经设计好了,开发一个软件来提高执行流程的效率。

Ubuntu 24安装最新版的Go语言开发环境的方法

Ubuntu 24.04(Noble Numbat)上安装 Go 语言有几种常见方式,2025-2026 年最推荐的方式是直接使用官方二进制包,这样可以拿到最新版本(目前通常是 1.24.x 或 1.25.x),而且最稳定、最容易升级。

下面给出目前最主流、最推荐的安装步骤:

推荐方式:官方二进制安装(最新版,强烈推荐)

1 打开终端,先清理旧版本(非常重要,避免冲突)

sudo rm -rf /usr/local/go

2 去官网查看最新版本(很重要!)

https://go.dev/dl

截至2026年1月,最新稳定版大概率是 go1.25.x 或更高。以 amd64 架构为例(绝大多数电脑都是这个),复制最新版下载链接。

示例(请替换成你看到的最新版):

# 进入下载目录(也可以随便哪个目录)
cd ~/Downloads

# 下载(把版本号改成最新的)
wget https://go.dev/dl/go1.25.6.linux-amd64.tar.gz

3 解压到 /usr/local(官方推荐位置)

sudo tar -C /usr/local -xzf go1.25.6.linux-amd64.tar.gz

4 把 Go 加到 PATH(永久生效):

# 打开配置文件(zsh 用 .zshrc,bash 用 .bashrc)
vim ~/.bashrc

在文件末尾加入这一行:

export PATH=$PATH:/usr/local/go/bin

保存退出后,立即生效:

source ~/.bashrc

5 验证安装是否成功

go version

应该看到类似输出:

go version go1.25.6 linux/amd64

再检查Go环境变量是否正常:

go env

其他可选的Go语言安装方式

1 sudo apt install golang-go # 从Ubuntu 默认仓库安装,但版本偏旧

2 PPA: longsleep/golang-backports # 版本比较新

3 sudo snap install go –classic # 版本比较新,snap启动稍慢,路径较奇怪

Tips

  • 想升级Go → 直接重复上面步骤,先删掉旧的 /usr/local/go,再下载新版覆盖即可。
  • 多版本共存 → 推荐使用 asdfmise 版本管理工具。
  • 公司/团队要求特定版本 → 也建议用 asdf/mise,而不是全局覆盖。

Ubuntu 24系统PHP 8.3安装Swoole扩展的方法

在 Ubuntu 24.04(Noble Numbat)上安装 Swoole 扩展(PHP 8.3),目前最稳定、推荐的方式有两种:

1 首选方式:使用 Ondřej Surý 的 PPA 仓库(他维护了大量 PHP 扩展的预编译包,包括 swoole 6.1.4+,已支持 PHP 8.3),安装最简单、无需编译、更新方便。

2 备选方式:用 pecl 从源码编译安装(如果 PPA 版本不满足需求,或想用最新 master 分支)。

Swoole 官方仓库已转向维护较少的 OpenSwoole 分支,但大多数项目仍使用原版 swoole(pecl/swoole 或 PPA 中的 php-swoole)。

方式一:使用 PPA 安装(强烈推荐,5 分钟搞定)

1 添加 Ondřej Surý 的 PPA(如果之前没加过):

sudo add-apt-repository ppa:ondrej/php
sudo apt update

2 安装 Swoole 扩展:

sudo apt install php8.3-swoole

这会自动安装最新可用版本(截至 2025 年底,已有 6.1.4+ 支持 PHP 8.3)。

3 启用扩展(通过PPA包安装的扩展通常自动启用,但保险起见):

sudo phpenmod swoole

或手动在 php.ini 添加。

4 验证是否安装成功:

php -m | grep swoole

如果输出:

swoole

就说明安装swoole扩展成功。

更详细检查:

php -i | grep -i swoole

看到 swoole support => enabled 及版本信息即表示安装成功。

推荐再运行一个简单脚本进行测试:

<?php
echo swoole_version() . PHP_EOL;
var_dump(extension_loaded('swoole'));
?>

执行 php test.php

5 重启 PHP 服务:

sudo systemctl restart php8.3-fpm   # Nginx + FPM 最常见
sudo systemctl restart apache2      # 如果用 Apache

方式二:用 pecl 从源码编译安装(如果需要最新版或自定义)

1 安装编译依赖(非常重要,Ubuntu 24.04 上缺这些会编译失败):

sudo apt update
sudo apt install php8.3-dev php-pear libssl-dev zlib1g-dev libcurl4-openssl-dev
sudo apt install gcc g++ make   # 基本编译工具

如果要启用协程钩子、HTTP2、MySQL 等高级功能,还可加:

sudo apt install libbrotli-dev libnghttp2-dev

2 更新 pecl 频道(避免旧缓存问题):

sudo pecl channel-update pecl.php.net

3 安装 Swoole(推荐指定稳定版,如 5.1.x 或 6.0.x,根据项目需求):

sudo pecl install swoole

或指定版本(例如最新稳定版):

sudo pecl install swoole-6.1.4

安装过程会询问是否启用各种特性(默认回车即可,大部分推荐启用):

enable sockets support? [yes] → yes
enable openssl support? [yes] → yes
enable http2 support? [yes] → yes(需 libnghttp2-dev)
enable brotli? [no] → yes(需 libbrotli-dev)
…

4 启用扩展

用 phpenmod(推荐做法):

sudo phpenmod swoole

或手动编辑 php.ini(CLI 和 FPM 分别处理):

sudo nano /etc/php/8.3/cli/php.ini
sudo nano /etc/php/8.3/fpm/php.ini

添加以下一行:

extension=swoole.so

5 验证是否安装成功:

php -m | grep swoole

如果输出:

swoole

就说明安装swoole扩展成功。

更详细检查:

php -i | grep -i swoole

看到 swoole support => enabled 及版本信息即表示安装成功。

推荐再运行一个简单脚本进行测试:

<?php
echo swoole_version() . PHP_EOL;
var_dump(extension_loaded('swoole'));
?>

执行 php test.php

6 重启 PHP 服务:

sudo systemctl restart php8.3-fpm   # Nginx + FPM 最常见
sudo systemctl restart apache2      # 如果用 Apache

注意事项与常见问题

  • 依赖缺失:编译失败最常见原因是缺少 php8.3-dev 或 libssl-dev。
  • 内存/CPU:编译 Swoole 需要 1-2GB 内存,低配 VPS 可能卡住或失败。
  • OpenSwoole vs Swoole:如果你项目明确需要 OpenSwoole(更活跃的分支),改用 pecl install openswoole 或 PPA 中的 php8.3-openswoole(如果有)。
  • 生产环境:Swoole 常用于常驻进程,建议用 Supervisor 或 systemd 管理服务,不要直接用 php-fpm。
  • 性能调优:安装后可在 php.ini 添加:

swoole.use_shortname = On    ; 允许 \co、\go 等短名(可选)

参考

官方文档安装Swoole

布鲁克定律(Brook’s Law):为已经延期的软件项目增加人手只会让项目延期得更厉害

如果一个项目出现了延期,只是简单地增加人手很可能会带来灾难性的后果。对编程效率、软件开发方法、技术架构等因素进行评审总是会带来更好的结果。如果没有,那说明霍夫施塔特定律也在起作用。

霍夫施塔特定律(Hofstadter’s Law)由 Douglas Hofstadter 提出,并以他的名字命名。这个定律指出:即使你考虑到了霍夫施塔特定律,项目的实际完成时间总是比预期的要长。

这个“定律”是关于准确预估完成复杂任务所需时间的难度。这个定律具有递归性,反映了预估复杂项目的难度,尽管你可能已经做出了最大的努力,而且也知道任务的复杂性。

这就是为什么在进行项目预估时必须要有一个缓冲区。

软件开发后期,添加人力只会使项目开发得更慢。

这个定律表明,在许多情况下,试图通过增加人力来加速已延期项目的交付,将会使项目交付得更晚。布鲁克斯也明白,这是一种过度简化。但一般的论据是,新资源的时间增加和通信开销,会在短期内使开发速度减慢。而且,许多任务是密不可分的,换句话说,这样可以使更多的资源之间能轻易分配,这也意味着潜在的速度增长也更低。

谚语:十个女人不能在一个月内生一个孩子。与布鲁克斯法则同出一辙,特别是某些不可分割或者并行的工作。

这也是《人月神话》的中心主题。

参考

https://cloud.tencent.com/developer/article/1421055?from=article.detail.1525574

https://github.com/nusr/hacker-laws-zh

https://en.m.wikipedia.org/wiki/Brooks%27s_law

怎么判断当前使用的ssh命令是否是OpenSSH的?

要判断当前系统中使用的 ssh 命令是否是 OpenSSH 实现(OpenSSH 是 SSH 协议的最常见开源版本,在 Linux、macOS 等系统默认使用),可以采用以下方法。这些方法基于命令输出或文件检查,适用于大多数 Unix-like 系统(如 Ubuntu、macOS)。如果您使用 Windows,可能需调整为 PowerShell 或检查 PuTTY 等工具。

方法 1: 使用版本检查命令(推荐,最简单)

运行以下命令:

ssh -V

预期输出:

  • 如果是 OpenSSH,会显示类似:

OpenSSH_9.6p1, OpenSSL 3.0.13 30 Jan 2024

开头以 “OpenSSH_” 表示是 OpenSSH 版本(数字如 9.6p1 因系统而异)。

  • 如果不是 OpenSSH(如 Dropbear 或其他实现),输出可能不同,例如:

Dropbear: Dropbear ssh-2024.85

方法 2: 检查命令路径和链接

运行:

which ssh

输出路径如 /usr/bin/ssh(Ubuntu 默认)。

然后检查文件类型:

ls -l /usr/bin/ssh  # 替换为实际路径

如果是符号链接指向 OpenSSH 二进制(如 /usr/bin/ssh -> /usr/sbin/openssh-ssh),则可能是 OpenSSH。

或使用:

file /usr/bin/ssh

输出中包含 “ELF executable” 和架构信息,但不直接确认;结合版本检查使用。

方法 3: 检查安装包(适用于 Ubuntu/Debian 系统)

运行:

dpkg -S $(which ssh)

如果输出包含 “openssh-client” 或类似包名,则是 OpenSSH。

或者:

apt list --installed | grep openssh

看到 “openssh-client” 或 “openssh-server” 表示已安装 OpenSSH。

方法 4: 检查帮助或手册

运行:

ssh --help

OpenSSH 的帮助输出会列出特定选项(如 -V, -vvv),与其他实现(如 lsh 或 Tectia)不同。

常见注意事项

  • 多实现共存:如果系统有多个 SSH(如通过 Homebrew 在 macOS 安装),使用 which ssh 确认当前 PATH 中的是哪个。
  • 如果不是 OpenSSH:可能是 Dropbear(轻量级,用于嵌入式系统)、PuTTY(Windows GUI 工具)或其他商业实现(如 Tectia)。这些通常不支持所有 OpenSSH 选项。
  • 测试连接:运行 ssh -vvv user@host(详细模式),日志中会显示”OpenSSH”,如果是该实现。
  • 如果命令不存在,安装 OpenSSH:Ubuntu 上运行 sudo apt install openssh-client
  • Windows 11企业版自带OpenSSH。

The ~/.ssh/config File: Make Your SSH Life 10× Easier (and Safer)

If you SSH into multiple machines every day and you’re still typing long commands like

ssh -i ~/.ssh/special_key -p 2222 [email protected]

…then you are suffering needlessly.

The ~/.ssh/config file is the single best way to stop that pain. It’s a per-user OpenSSH client configuration file (usually at /home/yourname/.ssh/config or ~/.ssh/config on macOS/Linux), and it lets you centralize all your connection logic so you rarely need flags anymore.

What it actually does (the good parts)
1 Host aliases / nicknames
Turn ugly connection strings into one nice short name.

Host prod-db
    HostName 10.88.12.45
    User admin
    Port 2222
    IdentityFile ~/.ssh/prod_rsa

After that, you just type:

ssh prod-db

2 Common options you almost always want

  • User — default username
  • Port — non-22 ports
  • IdentityFile — which key to offer (and only that key if you pair it with IdentitiesOnly yes)
  • ProxyJump — jump hosts / bastions (the modern replacement for ProxyCommand)

Example with a bastion:

Host internal-server
    HostName 192.168.77.22
    User deploy
    ProxyJump bastion.corp.example.com

3 Wildcards & patterns for groups of hosts
Very powerful once you have 10+ machines with similar setup.

Host *.staging.example.com
    User staging
    IdentityFile ~/.ssh/staging_key
    ServerAliveInterval 30

Host prod-*
    IdentitiesOnly yes
    IdentityFile ~/.ssh/prod_ed25519

4 Security & hardening tricks (things people usually learn the hard way)

Host untrusted-host
    StrictHostKeyChecking accept-new
    UserKnownHostsFile /dev/null     # only for throwaway/testing hosts!

Host *
    # Good defaults everyone should consider
    ServerAliveInterval 60
    ServerAliveCountMax 3
    Compression yes                # sometimes helps a lot on slow links
    ForwardAgent no                # safer default nowadays

Quick example people actually use

# ~/.ssh/config

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 5
    AddKeysToAgent yes
    UseKeychain yes               # macOS only, keeps passphrase in keychain

Host jump
    HostName jump.corp.example.com
    User jumpuser

Host *.internal
    ProxyJump jump
    User app
    IdentityFile ~/.ssh/internal_ed25519

Host laptop
    HostName 192.168.1.88
    User pi
    Port 8822

Important gotchas / pro tips
1 Permissions must be 600: chmod 600 ~/.ssh/config
OpenSSH will silently ignore the file if it’s too permissive — very common source of “why isn’t my config working?” pain.

2 User-level ~/.ssh/config overrides /etc/ssh/ssh_config

3 The file is not shell script — no variables, no conditionals (except the limited Match blocks in newer OpenSSH versions)

4 You can split config into multiple files with Include (OpenSSH ≥7.3):

Include ~/.ssh/config.d/*.conf

Once you start using it properly, going back to flag-heavy SSH feels like using vi without a .vimrc. Highly recommended.

What are your favorite ~/.ssh/config tricks?

~/.ssh/config 文件的作用

~/.ssh/config 文件是 OpenSSH 客户端的配置文件,位于用户主目录下的 .ssh 子目录中(例如 /home/username/.ssh/config)。它允许用户自定义 SSH 连接的行为,而无需每次连接时手动指定选项。该文件的作用主要包括简化 SSH 操作、提升安全性和管理多个主机的连接配置。

主要作用

  • 简化命令:通过定义主机别名(Host),可以将复杂的连接参数封装起来。例如,将一个远程服务器的 IP、端口、用户名等预设为一个短名称,以后只需用 ssh alias 即可连接,而无需输入 ssh -p 2222 [email protected]
  • 自定义连接参数:支持设置各种 SSH 选项,如:

端口(Port):指定非标准端口。

用户名(User):默认登录用户。

密钥文件(IdentityFile):指定私钥路径,避免每次手动加载。

代理跳板(ProxyJump):配置跳板机连接。

其他高级选项:如 KeepAlive、Compression 等,用于优化连接稳定性或性能。

  • 提升安全性:可以限制特定主机的认证方式(如 IdentitiesOnly yes,只使用指定密钥),或禁用不安全的选项(如 StrictHostKeyChecking no,但不推荐)。
  • 主机匹配:支持通配符(如 Host *.example.com),对多个相似主机应用同一配置。

文件格式示例

文件是纯文本,使用键值对格式(不区分大小写)。示例:

Host myserver
    HostName 192.168.1.100
    User myuser
    Port 2222
    IdentityFile ~/.ssh/my_private_key

注意事项

  • 文件权限应为 600(chmod 600 ~/.ssh/config),以确保安全。
  • 如果文件不存在,可以手动创建。
  • 系统级配置在 /etc/ssh/ssh_config,但用户级 ~/.ssh/config 优先级更高。
  • 适用于 ssh、scp、sftp 等命令。

SEO技术之前端技术选型

前端页面使用静态页面(SSG)方式部署,是SEO最友好的。

前端页面使用服务器端渲染(SSR)方式呈现给搜索引擎,SEO次优。

如果你的前端主应用必须是使用Vue.js或React.js等框架开发的单页应用(SPA),但还有其他的营销相关页面 (落地页、关于页、wiki、博客等),请单独部署这些页面!理想情况下,营销页面应该是包含尽可能少js代码的静态HTML,并用静态页面(SSG)方式部署。