在Dokploy中通过Cloudflare Tunnel发布应用

通过 Cloudflare Tunnel,你可以不需要公网 IP、不需要在路由器/防火墙开启 80 或 443 端口,就能安全地将 Dokploy 上的应用发布到互联网。 核心流程图 用户 -> Cloudflare 域名 (HTTPS) -> Cloudflare 隧道 -> Docker 内部网络 (HTTP) -> 你的应用容器 第一步:在 Cloudflare 创建隧道 (Tunnel) 登录 Cloudflare Zero Trust 。 进入 Networks -> Tunnels -> Create a Tunnel。 选择 Cloudflared,起个名字(如 my-server)。 在安装页面,找到 Connector Token(那一长串字符串),复制备用。 第二步:在 Dokploy 中部署隧道服务 在 Dokploy 中新建一个 Compose 服务(建议命名为 cloudflare-tunnel),使用以下配置: services: cloudflared: image: 'docker.1ms.run/cloudflare/cloudflared:latest' environment: - 'TUNNEL_TOKEN=你的TOKEN' # 建议在 Environment 变量中设置 networks: - dokploy-network # 必须加入此网络 restart: unless-stopped command: ["tunnel", "--no-autoupdate", "run"] networks: dokploy-network: external: true 第三步:部署应用 (以 Excalidraw 为例) 部署应用时,务必确保它与隧道在同一个 Docker 网络中,以便隧道能通过“服务名”找到它。 ...

2026-01-23 · 1 分钟 · czyt

Git Filer Repo快速指南

本文使用claude code编写,旨在提供一个详尽的 git-filter-repo 使用指南,涵盖安装、基础概念、路径和内容过滤、实用场景、高级功能、安全机制、完整工作流示例、故障排除、性能优化、常见错误与陷阱、与其他工具配合以及最佳实践总结等方面的内容。 什么是 git-filter-repo? git-filter-repo 是一个快速、功能强大的 Git 历史重写工具,是 git filter-branch 的官方推荐替代品。它由 Git 项目贡献者 Elijah Newren 开发,速度比 filter-branch 快 10-100 倍以上。 核心原理: git fast-export <options> | filter | git fast-import <options> git-filter-repo 同时扮演管道编排者和中间过滤器的角色,基于 fast-export 和 fast-import 实现高效的历史重写。 为什么选择 git-filter-repo? vs git filter-branch 特性 git filter-branch git-filter-repo 速度 极慢(大型仓库几乎不可用) 快 10-100 倍 安全性 易出错,可能静默损坏数据 内置多重安全检查 易用性 复杂的 shell 语法 简洁的命令行参数 跨平台 依赖 shell,跨平台问题多 纯 Python,跨平台一致 官方态度 已废弃,不推荐使用 Git 官方推荐 Git 官方警告: filter-branch 的问题无法向后兼容地修复,强烈建议停止使用。 ...

2026-01-13 · 15 分钟 · czyt

Calude Code编写的Ent ORM 完整指南

本文由claude code生成。作为备忘录和分享,欢迎指正和补充。 一、Ent简介 Ent是一个简单但功能强大的实体框架,用于Go语言,使构建和维护具有大型数据模型的应用程序变得容易。 Ent是由Meta(Facebook)开源团队构建的ORM框架,提供了一个API,用于将任何数据库模式建模为Go对象。 核心特性 Ent的主要特性包括: Schema As Code:将任何数据库模式建模为Go对象 轻松遍历任何图结构:运行查询、聚合并轻松遍历任何图结构 静态类型和显式API:100%静态类型和显式API,通过代码生成实现 多存储驱动支持:支持MySQL、PostgreSQL、SQLite和Gremlin 易于扩展:使用Go模板简单扩展和自定义 Ent是一个相当新的ORM,使用代码优先的方法,在Go代码中定义模式。Ent之所以流行,是因为它能够优雅地处理复杂的数据模型和关系。 二、快速开始 2.1 安装Ent # 初始化Go模块 go mod init myapp # 安装ent CLI工具 go install entgo.io/ent/cmd/ent@latest # 或者使用go get go get entgo.io/ent/cmd/ent 2.2 创建第一个Schema # 创建User实体 ent new User 这会在 ent/schema/ 目录下生成一个基础的schema文件: package schema import ( "entgo.io/ent" "entgo.io/ent/schema/field" ) // User holds the schema definition for the User entity. type User struct { ent.Schema } // Fields of the User. func (User) Fields() []ent.Field { return []ent.Field{ field.String("name"). NotEmpty(), field.Int("age"). Positive(), field.String("email"). Unique(), field.Time("created_at"). Default(time.Now), } } // Edges of the User. func (User) Edges() []ent.Edge { return nil } 2.3 生成代码 go generate ./ent 2.4 连接数据库并使用 package main import ( "context" "log" "myapp/ent" _ "github.com/lib/pq" // PostgreSQL // _ "github.com/go-sql-driver/mysql" // MySQL // _ "github.com/mattn/go-sqlite3" // SQLite ) func main() { // 连接PostgreSQL client, err := ent.Open("postgres", "host=localhost port=5432 user=postgres dbname=myapp password=password sslmode=disable") if err != nil { log.Fatalf("failed opening connection to postgres: %v", err) } defer client.Close() // 运行自动迁移 if err := client.Schema.Create(context.Background()); err != nil { log.Fatalf("failed creating schema resources: %v", err) } ctx := context.Background() // 创建用户 user, err := client.User. Create(). SetName("张三"). SetAge(30). SetEmail("zhangsan@example.com"). Save(ctx) if err != nil { log.Fatalf("failed creating user: %v", err) } log.Println("user was created: ", user) } 2.5 使用SQLite3(非CGO驱动) 📋 使用场景 为什么使用非CGO的SQLite驱动? ...

2025-12-12 · 51 分钟 · czyt

在Go里面实现Google和Apple OAuth登录

本文由claude code编写,仅供参考。 在现代应用开发中,提供第三方登录已经成为标配功能。本文将详细介绍如何在Go语言中实现Google和Apple的OAuth登录,以及如何处理iOS和Android的原生登录。 一、OAuth 2.0 基础概念 OAuth 2.0是一个授权框架,允许应用在用户授权的情况下访问用户在第三方服务上的资源,而无需获取用户的密码。主要流程包括: 授权请求:引导用户到OAuth提供商的授权页面 授权确认:用户同意授权 获取授权码:重定向回应用并携带授权码 交换令牌:使用授权码换取访问令牌 访问资源:使用访问令牌获取用户信息 二、Google OAuth登录实现 2.1 前期准备 首先需要在Google Cloud Console创建项目并配置OAuth 2.0凭据: 访问 Google Cloud Console 创建新项目或选择现有项目 启用Google+ API或Google Identity服务 创建OAuth 2.0客户端ID(Web应用、iOS、Android分别创建) 配置授权重定向URI 2.2 安装依赖 go get golang.org/x/oauth2 go get golang.org/x/oauth2/google go get google.golang.org/api/oauth2/v2 2.3 Web端Google登录实现 package main import ( "context" "encoding/json" "fmt" "log" "net/http" "os" "golang.org/x/oauth2" "golang.org/x/oauth2/google" oauth2api "google.golang.org/api/oauth2/v2" "google.golang.org/api/option" ) var googleOauthConfig *oauth2.Config func init() { googleOauthConfig = &oauth2.Config{ ClientID: os.Getenv("GOOGLE_CLIENT_ID"), ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"), RedirectURL: "http://localhost:8080/auth/google/callback", Scopes: []string{ "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", }, Endpoint: google.Endpoint, } } // 处理Google登录请求 func handleGoogleLogin(w http.ResponseWriter, r *http.Request) { // 生成随机state参数,防止CSRF攻击 state := generateRandomState() // 将state存储到session中 saveStateToSession(r, w, state) // 生成授权URL url := googleOauthConfig.AuthCodeURL(state, oauth2.AccessTypeOffline) http.Redirect(w, r, url, http.StatusTemporaryRedirect) } // 处理Google回调 func handleGoogleCallback(w http.ResponseWriter, r *http.Request) { // 验证state参数 state := r.FormValue("state") savedState := getStateFromSession(r) if state != savedState { http.Error(w, "Invalid state parameter", http.StatusBadRequest) return } // 获取授权码 code := r.FormValue("code") if code == "" { http.Error(w, "Code not found", http.StatusBadRequest) return } // 交换令牌 token, err := googleOauthConfig.Exchange(context.Background(), code) if err != nil { http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError) return } // 获取用户信息 userInfo, err := getGoogleUserInfo(token) if err != nil { http.Error(w, "Failed to get user info: "+err.Error(), http.StatusInternalServerError) return } // 处理用户信息(创建或更新用户) handleUserLogin(w, r, userInfo) } // 获取Google用户信息 func getGoogleUserInfo(token *oauth2.Token) (*GoogleUserInfo, error) { ctx := context.Background() // 创建OAuth2服务 oauth2Service, err := oauth2api.NewService(ctx, option.WithTokenSource(googleOauthConfig.TokenSource(ctx, token))) if err != nil { return nil, err } // 获取用户信息 userInfo, err := oauth2Service.Userinfo.Get().Do() if err != nil { return nil, err } return &GoogleUserInfo{ ID: userInfo.Id, Email: userInfo.Email, VerifiedEmail: userInfo.VerifiedEmail, Name: userInfo.Name, GivenName: userInfo.GivenName, FamilyName: userInfo.FamilyName, Picture: userInfo.Picture, }, nil } type GoogleUserInfo struct { ID string `json:"id"` Email string `json:"email"` VerifiedEmail bool `json:"verified_email"` Name string `json:"name"` GivenName string `json:"given_name"` FamilyName string `json:"family_name"` Picture string `json:"picture"` } 2.4 Android/iOS原生Google登录处理 对于移动端原生登录,客户端会使用Google SDK获取ID Token,然后发送给后端验证: ...

2025-12-12 · 15 分钟 · czyt

Homebrew Tap 仓库简明指南

本文为Claude整理编写。 什么是 Homebrew Tap Homebrew Tap 是第三方的 Homebrew 软件包仓库。通过创建自己的 Tap,你可以发布和分发自己的软件包,而不需要将它们提交到官方的 Homebrew 仓库。 Tap 的命名规则: homebrew-<tapname> 用户使用时的格式:username/tapname/软件名 Formula vs Casks:核心概念 这是 Homebrew 中最重要的区别,理解这一点对于正确组织你的 Tap 至关重要。 Formula(公式) 用途: 安装命令行工具、从源代码编译的软件、开发库和服务 特点: 可以从源代码编译或安装预编译二进制 安装到 /usr/local/bin(Intel)或 /opt/homebrew/bin(Apple Silicon) 在终端中运行 文件放在 Formula/ 目录 安装命令: brew install git brew install python brew install myapp 适用场景: ✅ 命令行工具(git, wget, curl) ✅ 编程语言(python, node, ruby) ✅ 开发库(openssl, libpq) ✅ 后台服务(redis, nginx, postgresql) ✅ 系统工具和实用程序 Casks(桶) 用途: 安装 macOS 原生应用程序、字体、驱动等 ...

2025-11-21 · 9 分钟 · czyt

Hertz使用笔记

Hertz的优缺点 优点 中文社区维护 稳定,字节产品,有相关的开源项目参考,比如coze和coze studio hz的模板支持,使得代码生成更加灵活 缺点 工程体验上,不如go-kratos等项目。比如不能很好得支持buf等第三方生态。代码生成的使用场景,如多service模式下体验不好。 Template 模板 之所以将模板放在第一,是因为Hertz里面模板是过不去的坎。😄官方的一个mvc的template 或者 cwgo内置的模板 自动生成路由注册 新建一个template/package.yaml layouts: # 覆盖默认 router.go 模板 # 关键:将 Register 函数名改为包含服务名的唯一名称 - path: router.go delims: ['{{', '}}'] body: |- // Code generated by hertz generator. DO NOT EDIT. package {{$.PackageName}} import ( "github.com/cloudwego/hertz/pkg/app/server" {{- range $k, $v := .HandlerPackages}} {{$k}} "{{$v}}" {{- end}} ) /* This file will register all the routes of the services in the master idl. And it will update automatically when you use the "update" command for the idl. So don't modify the contents of the file, or your code will be deleted when it is updated. */ {{define "g"}} {{- if eq .Path "/"}}r {{- else}}{{.GroupName}}{{end}} {{- end}} {{define "G"}} {{- if ne .Handler ""}} {{- .GroupName}}.{{.HttpMethod}}("{{.Path}}", append({{.HandlerMiddleware}}Mw(), {{.Handler}})...) {{- end}} {{- if ne (len .Children) 0}} {{.MiddleWare}} := {{template "g" .}}.Group("{{.Path}}", {{.GroupMiddleware}}Mw()...) {{- end}} {{- range $_, $router := .Children}} {{- if ne .Handler ""}} {{template "G" $router}} {{- else}} { {{template "G" $router}} } {{- end}} {{- end}} {{- end}} // Register register routes based on the IDL 'api.${HTTP Method}' annotation. func Register(r *server.Hertz) { {{template "G" .Router}} } # 覆盖 register.go 模板 # 在这个文件中聚合所有服务的 Register 调用 - path: register.go delims: ['{{', '}}'] update_behavior: type: "append" append_key: "service" insert_key: "{{.ServiceName}}" append_tpl: | {{$.DepPkgAlias}}.Register(r) body: |- // Code generated by hertz generator. DO NOT EDIT. package {{.PackageName}} import ( "github.com/cloudwego/hertz/pkg/app/server" {{$.DepPkgAlias}} "{{$.DepPkg}}" ) // GeneratedRegister registers routers generated by IDL. func GeneratedRegister(r *server.Hertz){ //INSERT_POINT: DO NOT DELETE THIS LINE! {{$.DepPkgAlias}}.Register(r) } 然后service proto都定义为不同的go package包, admin.proto ...

2025-10-30 · 3 分钟 · czyt

Omarchy 使用笔记

omarchy是DHH发布的一款Arch内核的Linux发行版。最近安装了下,稍作记录 特色功能 命令行 可以使用 eza替换ls 快捷键 导航快捷键 Super + Space:应用启动器 Super + Alt + Space:Omarchy 控制菜单 Super + Escape:锁定、暂停、重启、关机 Super + Ctrl + L:锁定计算机 Super + W:关闭窗口 Ctrl + Alt + Del:关闭所有窗口 Super + T:切换窗口的平铺/浮动模式 Super + O:切换窗口为粘性浮动模式 Super + F:全屏显示 Super + Alt + F:全宽度显示 工作区快捷键 Super + 1/2/3/4:跳转到指定工作区 Super + Tab:跳转到下一个工作区 Super + Shift + Tab:跳转到上一个工作区 Super + Ctrl + Tab:跳转到之前的工作区 Super + Shift + 1/2/3/4:移动窗口到指定工作区 Super + Shift + Alt + 方向键:将工作区移动到指定显示器 窗口管理快捷键 Super + 方向键:将焦点移动到指定方向的窗口 Super + Shift + 方向键:与指定方向的窗口交换位置 Super + Equal:向左扩展窗口 Super + Minus:向右扩展窗口 Super + Shift + Equal:向下扩展窗口 Super + Shift + Minus:向上扩展窗口 Super + G:切换窗口分组 Super + Alt + G:将窗口移出分组 Super + Alt + Tab:在分组中的窗口间循环切换 Super + Alt + 1/2/3/4:跳转到分组中的指定窗口 Super + Alt + 方向键:将窗口移动到指定方向的分组中 Super + Ctrl + 方向键:在平铺分组中的窗口间移动 Super + S:显示便签工作区覆盖层 Super + Alt + S:将窗口移动到便签工作区 系统控制快捷键 Super + Ctrl + A:音频控制(wiremix) Super + Ctrl + B:蓝牙控制(bluetui) Super + Ctrl + W:WiFi 控制(impala) Super + Ctrl + S:共享菜单(通过 LocalSend) Super + Ctrl + T:活动监视器(btop) 应用启动快捷键 Super + Return:终端 Super + Shift + B:浏览器 Super + Shift + Alt + B:浏览器(隐私/无痕模式) Super + Shift + F:文件管理器 Super + Shift + M:音乐(Spotify) Super + Shift + /:密码管理器(1password) Super + Shift + N:Neovim Super + Shift + C:日历(HEY) Super + Shift + E:邮件(HEY) Super + Shift + A:AI(ChatGPT) Super + Shift + G:消息(Signal) Super + Shift + Alt + G:消息(WhatsApp) Super + Shift + Ctrl + G:消息(Google) Super + Shift + D:Docker(LazyDocker) Super + Shift + O:Obsidian Super + Shift + X:X 通用剪贴板快捷键(统一系统) Super + C:复制 Super + X:剪切(终端中不可用) Super + V:粘贴 Super + Ctrl + V:剪贴板管理器 注意:在 Linux 上,通常需要在终端中使用 Ctrl + Shift + C/V 进行复制粘贴,而在其他地方使用 Ctrl + C/V。Omarchy 的统一剪贴板快捷键在所有地方都有效(文件管理器除外)。 ...

2025-09-18 · 17 分钟 · czyt

Arch NVIDIA 驱动故障排查与修复指南

本文基于warp Terminal的修复操作使用deepseek进行复盘 问题描述 在EndeavourOS系统更新后,显示器因NVIDIA驱动问题停止工作,主要症状如下: nvidia-smi 命令报错: NVIDIA-SMI 失败:无法与NVIDIA驱动通信 检测不到显示设备: xrandr --listproviders 提供方数量:0 内核模块缺失: modprobe: 致命错误:在/lib/modules/6.16.6-arch1-1中找不到nvidia模块 问题根源 版本不匹配 nvidia=580.82.07-2 与 nvidia-utils=580.82.07-1 版本不一致 内核兼容性问题 预编译的nvidia驱动不支持新内核(6.16.6-arch1-1) 驱动类型限制 标准nvidia软件包无法自动重建内核模块 完整解决方案 1. 排除问题包进行系统更新 paru -Syyu --ignore nvidia,nvidia-utils,nvidia-settings --noconfirm 2. 卸载问题驱动并安装DKMS版本 paru -R nvidia --noconfirm # 移除问题驱动包 paru -S nvidia-dkms --noconfirm # 安装DKMS版本 3. 加载NVIDIA模块并验证 sudo modprobe nvidia # 强制加载驱动模块 nvidia-smi # 验证驱动状态 预期输出示例: +-----------------------------------------------------------------------------+ | NVIDIA-SMI 580.82.07 驱动版本: 580.82.07 CUDA版本: 12.1 | |-------------------------------+----------------------+----------------------+ | GPU 名称 持久性| Bus-Id 显存使用 | 易失性非校正ECC | | 风扇 温度 性能 功耗上限 | 显存使用率 | GPU利用率 计算模式 | |===============================+======================+======================| | 0 NVIDIA RTX 3050 关闭 | 00000000:01:00.0 开启 | N/A | | N/A 45C 待机 10W / 115W | 200MiB / 4096MiB | 0% 默认 | +-------------------------------+----------------------+----------------------+ 技术对比:nvidia vs nvidia-dkms 特性 nvidia(预编译版) nvidia-dkms(动态版) 内核适配方式 静态(为特定内核预编译) 动态(自动重建模块) 维护难度 需手动更新 随内核变更自动适配 稳定性 适合固定内核系统 适合滚动更新系统 额外依赖 无 需要安装linux-headers 推荐使用场景 服务器/LTS系统 频繁更新内核的桌面环境 预防性措施 优先使用DKMS版本 paru -S nvidia-dkms linux-headers LTS内核用户替代方案 paru -S nvidia-lts 双显卡优化建议 安装Optimus管理器优化切换: sudo pacman -S optimus-manager 系统环境信息 操作系统: EndeavourOS (基于Arch Linux) 显卡配置: 独立显卡:NVIDIA GeForce RTX 3050 Mobile 集成显卡:Intel Iris Xe Graphics 显示器设置:eDP-1 @ 1920x1080分辨率 内核版本:6.16.6-arch1-1 经验总结 使用DKMS可解决90%因内核更新导致的驱动失效问题 注意检查驱动工具包版本一致性: pacman -Q nvidia nvidia-utils 双显卡系统可能需要额外配置才能正常切换

2025-09-11 · 1 分钟 · czyt

一些适合小朋友的电影合辑

资源整理来自网络,如有侵权,请联系我删除. 因为小朋友看不懂字幕,所以优先收集的是带多音轨的版本资源。 外国 蜘蛛侠 magnet:?xt=urn:btih:DF16B7D9B96E46D78DCC3241ECDBFA456C15CF90&dn=蜘蛛侠全家桶&tr=udp://tracker.openbittorrent.com:80/announce&tr=udp://tracker.opentrackr.org:1337/announce 哈利波特 magnet:?xt=urn:btih:BC9997161B52E3472156BBF5D51541E793BA8233&dn=[y5y4.com]哈利波特1-8合集.多语音轨字幕.珍藏版.Harry.Potter.Collection.2001-2011.BluRay.1080p.x265.10bit.DuoAudio-AIU 驯龙高手 magnet:?xt=urn:btih:53330826EE05220B5E79DDD3B734D6178DE69467&dn=【首发于高清影视之家 www.BBQDDQ.com】驯龙高手2[国粤英多音轨+简繁英双语字幕].How.to.Train.Your.Dragon.2.2014.UHD.BluRay.2160p.MultiAudio.DTS-X.MA.7.1.x265.10bit.HDR-ALT magnet:?xt=urn:btih:5E89BC62EA3443A7A28D4366A00CFA78959A0E32&dn=【首发于高清影视之家 www.BBQDDQ.com】驯龙高手3[国粤英多音轨+简繁英字幕].How.to.Train.Your.Dragon.The.Hidden.World.2019.UHD.BluRay.2160p.MultiAudio.TrueHD(Atmos).7.1.x265.10bit.HDR-ALT magnet:?xt=urn:btih:6F417913B9C669C5CBCC3C6FE1ABEE9D2F7BE953&dn=【首发于高清影视之家 www.BBQDDQ.com】驯龙高手[国粤英多音轨+简繁英字幕].How.To.Train.Your.Dragon.2010.UHD.BluRay.2160p.MultiAudio.DTS-X.MA.7.1.x265.10bit.HDR-ALT 漫威十年十八部大作中英双语 magnet:?xt=urn:btih:BE8EBED29654C90DDC59B2552E7A7FF5F4BB068B

2025-09-03 · 1 分钟 · czyt

在并发Go应用中保持顺序【译】

原文链接 https://destel.dev/blog/preserving-order-in-concurrent-go 并发是 Go 语言的一大优势,但它带来一个根本性的权衡:当多个 goroutine 同时处理数据时,自然顺序会被打乱。大多数情况下,这并无大碍——无序处理已足够,且更快速、更简单。 但有时,顺序至关重要。 当顺序至关重要 以下是三个需要保持顺序至关重要的实际场景: 实时日志增强 :您正在处理高流量的日志流,通过数据库或外部 API 为每个条目添加用户元数据。顺序处理无法跟上输入速率,但并发处理会打乱顺序,使得增强后的日志对依赖时间顺序的下游消费者变得不可用。 在文件列表中查找首个匹配项 :您需要从云存储下载文件列表,并找到包含特定字符串的第一个文件。并发下载速度更快,但完成顺序是乱序的——第 50 个文件可能比第 5 个文件先完成,因此您不能简单地返回找到的第一个匹配项,因为无法确定更早的文件是否也包含该字符串。 时间序列数据处理 :这个场景激发了我的原始实现。我需要下载 90 天的交易日志(每个约 600MB),提取部分数据,然后比较连续日期的数据以进行趋势分析。顺序下载需要数小时;并发下载可实现数量级的速度提升,但会破坏我进行比较所需的时间关联性。 挑战很明确:我们需要在不牺牲结果顺序可预测性的前提下获得并发处理的速度优势。这不仅是理论问题——更是影响实际大规模系统的现实约束。 本文将探讨我在生产级 Go 应用中开发并采用的三种方法。我们将构建一个并发的 OrderedMap 函数,它能在保持顺序的同时将输入通道转换为输出通道,并支持具有背压机制的无限流处理。通过对每种方法进行基准测试,我们将理解其权衡取舍,并在此过程中发现令人惊讶的性能洞见。 问题:为何并发会破坏顺序 让我们快速回顾一下为什么并发会打乱顺序。原因之一是各个 goroutine 处理任务的速度不同。另一个常见原因——我们无法预测 Go 运行时如何精确调度 goroutine。 例如,goroutine #2 可能在 goroutine #1 完成第 10 项之前就处理完了第 50 项,导致结果顺序错乱。这是并发处理的自然行为。 若想查看实际效果,这里有一个在 Go Playground 上的快速演示 。 设计理念:背压与缓冲的权衡 传统的顺序并发方法采用某种重排序缓冲区或队列。当工作线程计算出结果但尚不能写入输出时,该结果会被暂存于缓冲区中,直至能够按正确顺序写入。 在这种设计中,缓冲区通常可以无限制地增长。这种情况发生在: 输入存在倾斜 – 早期项目的处理时间比后续项目更长 下游消费者处理速度较慢 另一种常见方法是将所有结果暂存于内存中(切片/映射等)再进行排序。但我们今天的目标是构建一个流式解决方案,它能够: 最小化延迟 – 结果一旦准备就绪立即输出 处理无限输入流 – 支持任意大甚至无限的输入(例如从标准输入或网络流读取) 保持内存受限 – 避免不必要地在内存中累积结果 话虽如此,下面介绍的算法是背压优先的。如果工作协程还无法将结果写入输出通道,它就会阻塞。这种设计受内存限制,并保持了开发者对 Go 通道行为的预期。 ...

2025-09-02 · 9 分钟 · czyt