v2ex_hot_2026-01-24

V2EX 热门帖子

1. Claude Code 这种智能 CLI 相对于 Cursor 的优势在哪?为什么感觉前者是主流了?

当然不限于这两个,前者也可以是 OpenCode ,后者也可以是 Github Copilot ,总之分别代表 AI Agent IDE 和 AI CLI 。 我是 Windows 客户端开发,日常工作用的是 WPF 和 Qt5 ,Qt 也有部分工作是在信创 Linux 上做的。目前的疑惑就是 CLI 感觉对我用处不大。无论是 WPF 还是 Qt5 都是那种很依赖 IDE 的开发框架,几乎不会出现需要开发者自己操作命令行的场景。然后另一方面之前用过免费的 Cursor 和 Github Copilot ,非常喜欢智能 Tab 的功能,这个是 CLI 不具备的,而且我也不知道去哪里找平价的替代…… 另外我用了 Claude Code for VS Code 插件要好一点,你们不会觉得在终端里输入中午很别扭难受吗……

作者: WangLiCha | 发布时间: 2026-01-23 07:22


2. 微软内部正在鼓励员工使用 Claude Code

尽管微软对外依然在主推 Github Copilot ,但微软内部正在鼓励员工使用 Claude Code 。

原文:微软内部全面拥抱 Claude Code:AI 编码工具格局生变

作者: Fdyo | 发布时间: 2026-01-22 17:54


3. 大家的 NAS 都买了应急电源了没?

家里一台群晖 ds423+和一台小主机电脑改装的飞牛,昨天家里用厨房电器,搞得跳闸停电了,我回家一看,开机后还好都没坏,除了这次,这两年断断续续的停过两三次电,所以准备购买一台 ups NAS 电源。大家都装了没?有没有好的推荐,谢谢

作者: yuwancumian27149 | 发布时间: 2026-01-23 01:28


4. # 别再用 Nginx 配置折磨自己了,推荐 Zoraxy 让你 3 分钟搞定反向代理

别再用 Nginx 配置折磨自己了,推荐 Zoraxy 让你 3 分钟搞定反向代理

免责声明:本文中信息来源于网络,作者不保证其绝对正确性。读者在依据本文内容做出任何决策或行动前,应自行进行充分的调查与核实。对于因使用本文内容而产生的任何直接或间接损失,作者不承担任何责任。

本文为专业文章, 适合运维、开发、self-hosted 需求人员观看。


你有没有这种经历?

新部署了一个服务,要去改 Nginx 配置文件。再部署一个,又要改。改完还得nginx -s reload

有时候改错了语法,reload 失败,服务全挂了。

这时候你突然意识到:学 Nginx 配置语法的时间,比学做饭的时间还长。

别问我是怎么知道的。

Zoraxy001

现状

反向代理在运维、开发、self-hosted 场景中经常用到,目前 Nginx 、Caddy 、Traefik 是主流选择。它们有个共同点:需要改配置文件

语法要记,改完要重载,错了要排查。对于不想折腾配置文件的人来说,这门槛不低。

今天介绍一个不一样的选择:Zoraxy 最大特点是全 UI 操作,支持动态应用规则的反向代理。

1

4

Zoraxy 是什么

Zoraxy 是一款基于 go 编写的动态反向代理工具。

最大的特点:Web UI 管理,零配置文件

项目简介里写得很直白——这可能是最适合新手的反向代理管理器之一。

想到了 python 的 solgan: 人生苦短,我用 python

它不是药,但可能治好你的”配置文件恐惧症”。

让我想起一个笑话。

有人问医生:”我每天都要吃止痛药才能工作,怎么办?”

医生说:”那你就别工作了。”

Zoraxy 就是那个让你不用”吃止痛药”的选择——你不需要每天和配置文件较劲。

能做什么

  • 反向代理 :HTTP/2 、WebSocket 自动代理、虚拟目录、别名主机、自定义请求头、负载均衡。

  • SSL 证书 :ACME 自动申请、Let’s Encrypt 支持、DNS Challenge 。

  • 访问控制 :IP 黑白名单、国家/地区封禁。

  • 流代理 :TCP/UDP 代理。

  • 监控 :集成 Uptime Monitor ,实时主机健康检查。

  • 其他 :Web SSH 终端、插件系统、实时流量分析。

2 3 4 5 6 7 8 9

快速上手

安装

因为基于 go 编写,基本上主流系统上直接安装编译好的文件就成。以 Linux 为例:

wget https://github.com/tobychui/zoraxy/releases/latest/download/zoraxy_linux_amd64

chmod +x ./zoraxy_linux_amd64

sudo ./zoraxy_linux_amd64

启动后访问 http://localhost:8000 进行初始设置(无需配置文件,全部操作在 UI 中完成 )。

就这么简单。

配置反向代理

登录 Web 界面后,添加反向代理规则很简单:

  1. 填写域名(比如 ftp.server.local, 注意提前配置好你的 dns 指向)
  2. 填写目标地址(比如 http://192.168.1.100:3000
  3. 保存就动态生效了

就这么简单。

zoraxy004_createrules

zoraxy004_http

SSL 证书

Zoraxy 内置 ACME 客户端功能,支持 Let’s Encrypt 等服务商证书的自动申请:证书自动续期,不用担心过期。

下面以自定义 ACME 服务器为例,展示 ssl 证书的申请。

zoraxy005_ssl

Uptime Monitor

Zoraxy 还集成了主机健康检查功能。

实时监控服务可用性,支持 HTTP/TCP/UDP 检查,失败会告警。

在”Uptime Monitor”页面添加监控目标就行。

和 Nginx/Caddy 的区别

特性 Zoraxy Nginx Caddy
配置方式 Web UI 配置文件 配置文件
动态更新 ✅ 即时生效 ❌ 需 reload ✅ 自动
SSL 证书 ACME 自动 需手动配置 ACME 自动
学习曲线
插件系统
Uptime Monitor ✅ 内置

核心差异很明显:Zoraxy 全部通过 Web 界面操作,改完立即生效,不用重载服务。

不想记配置文件语法的话,这是最大的优势。

什么时候用 Zoraxy

总体来说,zoraxy 十分适合中小企业内部, 家用 self-hosted 场景。

人生苦短, 我用 zoraxy

适合

  • 家用 lab/自托管多个服务

  • 不想折腾配置文件

  • 需要快速添加/删除代理规则

  • 需要基本的健康检查

  • 新手入门反向代理

不适合

  • 需要极高性能( Nginx/Traefik 优化更好)

  • 需要复杂的高级配置

  • 配置即代码( IaC )需求

其他信息

Zoraxy 是开源项目,AGPL 许可。

因为 go 的特性支持跨平台:Windows 、Linux 、macOS 、ARM 设备、RISC-V 。也集成到 TrueNAS 、Umbrel 、YunoHost 等应用市场。

写在最后

Nginx/Caddy 依然是优秀的选择。

但如果你厌倦了改配置文件,想要更简单的管理方式,或者刚开始接触 self-hosted ,可以试试 Zoraxy 。

就像那个老笑话:当手里拿着锤子时,看什么都像钉子。

但有时候,你需要的不是更好的锤子,而是一把螺丝刀。

Zoraxy 就是那把螺丝刀——它不是要取代你的锤子,而是给你一个不同的选择。

希望小编文章能帮助到大家,欢迎关注本公众号;有问题留言交流。

其他

欢迎关注本公众号其他社媒平台

link_logo

点击以下链接关注我的数字名片!

https://muselink.cc/hamisay

“如果您觉得这篇文章对您或您的朋友有所帮助,不妨动动手指,关注我们、点赞并分享到朋友圈,让更多人受益。您的每一次互动都是对我们最大的支持和鼓励!”

作者: fz420 | 发布时间: 2026-01-23 06:49


5. 关于出海产品用到的 redis 选哪家

由于大厂研发出身,技术选型上我还是有些追求,目前我的项目使用 cloudflare/vercel 部署前端接入层,用 GKE 部署后端服务,很多人也会用到 redis ,如果从网络延迟来考虑服务之间的部署,应该首选 google 的 redis 服务,然后通过内网直连达到最低的延迟,但是 google 太贵了光是 GKE 就已经有一笔成本了,还没赚到钱就不想花这么高的成本再去一个边缘的服务上去,推荐一家几乎免费的 redis 服务商 upstash 首先他们提供了免费额度:存储 256 MB 的数据,每月可以发出 500 000 次命令,默认最大数据库数量是 1 个。这免费的门槛可能就够你用了,如果你有多个服务,之间需要隔离的话,需要注意的一点是他们不支持 redis db 的选择,默认只有一个 db ,要薅羊毛你可以用多个账号,每个账号创建一个 redis 实例。付费的话也很目前我从 GKE 的 us-central1 通过公网链接到 upstash 的实例在首次链接建立后,通过长连接执行 command 的延迟是 1ms ,几乎和内网没什么区别。upstash 首先他们提供了免费额度:

存储 256 MB 的数据,每月可以发出 500 000 次命令,默认最大数据库数量是 1 个。

这免费的门槛可能就够你用了,如果你有多个服务,之间需要隔离的话,需要注意的一点是他们不支持 redis db 的选择,默认只有一个 db ,要薅羊毛你可以用多个账号,每个账号创建一个 redis 实例。

付费的话也很便宜,如果你也嫌管理太多账号太麻烦,可以选择按使用量计费( PAY AS YOU GO ):

1 、按每 100 000 次约 0.20 美元计费(这个价格是读写命令总和,不包括某些内部操作命令)

2 、存储空间按每 GB 大约 0.25 美元计费(每个数据库第一个 GB 通常免费)

3 、带宽月度前 200 GB 免费,之后按每 GB 大约 0.03 美元收费

我的服务使用 redis 量很小,这么算几乎一个月只需要不到 10 块钱人民币,这个成本比起 google 要低太多了,它还有其他高阶套餐这里留给大家自己去探索吧。

目前我从 GKE 的 us-central1 通过公网链接到 upstash 的实例的 us-central1 地区,在首次链接建立后,通过长连接执行 command 的延迟是 1ms ,几乎和内网没什么区别。

作者: horanv | 发布时间: 2026-01-23 03:02


6. 求助,谁会用那个 mongoDB 的云数据库啊,帮看看咋链接报错呢

如题,node.js 链接数据库报错:

✗ MongoDB connection failed: Error: queryTxt ETIMEOUT cluster0.ev5vqfk.mongodb.net at QueryReqWrap.onresolve [as oncomplete] (node:internal/dns/promises:294:17) { errno: undefined, code: ‘ETIMEOUT’, syscall: ‘queryTxt’, hostname: ‘cluster0.ev5vqfk.mongodb.net‘ }

下面是我按照官网配置的数据库访问的 URL ,在数据库页面也已添加当前 IP 地址进白名单了 mongodb+srv://wdz_db_user:cbim2025@cluster0.ev5vqfk.mongodb.net/?appName=Cluster0

作者: azhi2007 | 发布时间: 2026-01-23 15:38


7. ai 时代, node.js 成为核心语言

作者: laodao | 发布时间: 2026-01-23 09:20


8. 这个 workany 是什么水平的项目,有大佬讲一下吗?看他的介绍我一句也看不懂;网站: https://github.com/workany-ai/workany

作者: walterggg | 发布时间: 2026-01-23 15:16


9. [Flutter 独立开发] 挑战千元机极限:纯客户端计算 K 线+指标,三星 A53 依然稳定 60+帧

[Flutter 独立开发] 挑战千元机极限:纯客户端计算 K 线+指标,三星 A53 实测 70 FPS

大家好,我是《交易学徒》的独立开发者,祝大家周末愉快!

做过金融类 App 的朋友都知道,移动端的 K 线图( Candlestick Chart ) 渲染一直是性能优化的“深水区”。

为了降低服务器成本和网络延迟,我做了一个“违背祖宗”的决定:完全依赖客户端算力。 所有的技术指标( MA, BOLL, MACD 等)计算,全部在移动端本地实时完成,不依赖后端返回计算结果。

这意味着,一台三星 A53 ( Exynos 1280 处理器,典型的千元机性能)不仅要负责 UI 绘制,还要在主线程实时遍历数组计算指标。

在这种“地狱模式”下,优化成果如何?

📉 性能实测:A53 跑分数据

测试设备 :三星 Galaxy A53 (Exynos 1280) 测试场景

  • GOLD 平均每秒 2.5 次报价
  • 加载 500 根 K 线数据
  • 同时开启 MA (移动平均线) + BOLL (布林带) + MACD 三组指标 + 图表网格
  • 所有指标数据均为 本地实时计算
  • 进行高频拖拽、缩放操作

实测结果

1. 三星 A53 (低端机代表)

A53 帧率测试图

70 FPS ! 在这种重负载下,UI 线程依然保持极高的流畅度,超过 60Hz 的及格线。对于一款千元机来说,这个渲染性能我已经非常满意了。

2. 三星 S25+ (旗舰机代表)

S25+ 帧率图

旗舰机毫无压力,贵的还是好哇。


🏛️ 技术挑战:为何 Dart 能抗住?

很多人对 Flutter 的印象还停留在“套壳性能差”。但实际上,通过合理的架构,Dart 的性能完全够用。我的优化核心思路是:UI 渲染与数据计算分离,用空间换时间。

1. 极致的分层渲染 (Layered Rendering)

我利用 Stack 将视图拆解为三个独立的渲染层级:

  • **Layer A (底层)**:静态 K 线与网格。这是最“重”的层(包含数千个顶点),只有在缩放或平移时才重绘。
  • **Layer B (中间层)**:技术指标 (MA, BOLL)。与 K 线同步,但逻辑分离。
  • Layer C (交互层) 这是优化的关键。包含当前的 Bid/Ask 价格线、十字光标。这一层极其轻量,且更新频率最高(每秒数次)。

通过 Stack + RepaintBoundary,实现了:价格跳动时,底层的几百根 K 线完全不需要参与重绘,GPU 只需要绘制那几条横线。

2. 动态 LOD (Level of Detail) 策略

在手机屏幕上展示 500 根 K 线时,GPU 光栅化压力巨大。 我在代码中加入了 LOD 策略:

  • Zoom In :渲染完整的 Candlestick(蜡烛图)。
  • Zoom Out :当可视区域数据点过多时,自动切换为 LineChart(收盘价连线)。

这极大地降低了 GPU 的顶点绘制数量,解决了缩放时的“卡顿感”。


📱 软件界面预览

目前的 UI 风格偏向现代扁平,针对移动端操作做了很多适配。

软件界面截图


🔗 下载与体验

软件目前已上架 Google Play ,名为“交易学徒” 。如果你对高性能 Flutter 开发或者交易感兴趣,欢迎下载体验。

🎁 V 友专属福利

感谢大家看完这么枯燥的技术分析。 人肉送 VIP :在评论区留下你的 用户 ID (在“我的”页面可以看到),我会手动为你开通 1 个月的 VIP 会员

欢迎大家对 UI 、交互或者技术实现提出建议,每一条我都会认真看!

作者: kai92zeng | 发布时间: 2026-01-23 08:15


10. 如果发现 AI 生成的代码有多个 bug , 怎么办?

方案 1:一次性告诉 AI 所有的 bug , 让它一次性修复

方案 2:每次只告诉 AI 一个 bug , 让它逐个修复

作者: Nexora | 发布时间: 2026-01-23 04:00


11. ChromeOS Flex,如何科学上网 ?

我在笔记本上,安装了 ChromeOS Flex ,请问如何科学上网 ?

我需要科学上网之后,登录我的谷歌账号。

在 ChromeOS Flex 中,目前,因不知如何进行科学上网,导柱无法登录我的谷歌账号,只能使用 [访客身份] 使用 ChromeOS Flex , 只能使用有限的功能。

作者: c2r5 | 发布时间: 2026-01-22 18:28


12. AI 除了写代码,在哪方面最能提升业务研发团队的工作效率?

公司对 AI 很看重,不仅为我们采购了企业版的 GitHub copilot ,kiro ,Claude code 用作日常开发,邀请这些供应商的技术团队来交流分享,还鼓励我们在其他方面使用 AI 技术,不少团队的 OKR 都包含 AI 相关的内容了,我这能想到的就是监控报警交给 AI 治理,你们有比较好的实践分享吗?

作者: yuanyao | 发布时间: 2026-01-23 14:53


13. 有没有便宜好用的服务器推荐

最近用了 claude code, 工作效率大大提升, 空闲的时间想自己弄个项目, 但是又不知道写啥, 想着先弄一台服务器试试, 便宜好用点的, 最好是国外的, 省的备案了

作者: anidxin23333 | 发布时间: 2026-01-23 10:12


14. Java 写的 Postman 替代品 EasyPostman 被阮一峰老师的科技爱好者周刊选中了

前几天看到有小伙伴的帖子说他的开源被阮一峰老师的科技爱好者周刊选中了,我上周也去投稿了我的 EasyPostman,很开心也被选中了。 https://www.ruanyifeng.com/blog/2026/01/weekly-issue-382.html

10 月份我发布的 用 Java 写了个开源的 Postman 替代品,本地存储 + Git 协作 https://www.v2ex.com/t/1167863

EasyPostman 是一款开源的 API 调试与性能测试工具,对标 Postman + JMeter ,专为开发者优化,界面简洁、功能强大,内置 Git 集成,支持团队协作与版本控制。

test

https://imgur.com/a/c91Y7m3

项目地址: https://github.com/lakernote/easy-postman

国内镜像: https://gitee.com/lakernote/easy-postman

作者: lakernote | 发布时间: 2026-01-23 01:18


15. 鹰角终末地外服出现问题的可能原因是什么?

开服上线前测试没有发现这个问题吗

作者: 404www | 发布时间: 2026-01-23 14:38


16. 发现一个邮件驱动的 APP

第一次看到这种类型的应用,没有网站。我根据邮件提示创建了一个属于自己的邮箱。[email protected].

  1. 只要向目标地址发送一封邮件,就可以每天获得 200M 的流量。
  2. 如果你发到我的这个邮箱,我就成为你的引荐人,referrer 。
  3. 如果你付费订阅,我可以获取 5%的充值款。

特点在于配置文件作为邮件的附件,几乎不会被切断联系。除非屏蔽邮箱地址。

我大体研究了一下,好像没有中心节点。也就是说攻击单个节点不会对其它节点造成影响。

作者: jianglibo | 发布时间: 2026-01-23 06:11


17. AI 时代如何证明个人项目的真实性?

背景

前天朋友提供一个内推岗,这个公司蛮不错的,规模大待遇好还不是外包也不是有争议的 web3 ,他在里面工作,说招好几个月了还是没人去。我有个个人微服务项目准备拿去应聘,然而推荐后说没办法还是得垂直经验,因为现在有 AI 生成代码很简单,个人项目很容易被认为是 AI 代工。

项目介绍

项目原先是通过网课教程做的但不符合生产要求被我全部推翻重写,原来是 go micro 2.9.1 现在是 go micro 4 ,所有服务都是领域驱动,改过框架源码,链路追踪、监控、日志系统、架构等全部一人完成,期间技术栈做了很大的调整,一共迭代 6 个版本,目前是 6.1 ,耗时 3 个月,至今仍在迭代,有部分自编组件。包含压测报告、决策记录、变更日志和自述文件(含项目介绍及部署指南),用 Github Project 管理项目,2 周一版,部署在阿里云 K8S 集群上,使用超过 15 个组件,还用到 LUA 脚本。服务是模拟支付回调扣减库存过程,每个服务 2 个副本,单个 Pod 上限为单核 CPU + 512M 内存,压测 1596Qps ,P99 为 84ms 。

不存在 AI 代工

我开发过程中主要是用 AI 推荐轻量级工具并分析其难度,代码大部分还是自己写,因为 go micro 做 EDA 架构的案例本身就少得可怜直接导致 AI 生成的代码不靠谱,最后还是被我的方案优雅地取代。开发过程中每个版本都是巨大的挑战。

请问各位大佬如何证明个人项目不是 AI 代工以实现成功转型 Golang 开发?

作者: zhanshen1614 | 发布时间: 2026-01-23 03:31


18. 移动 NAS 推荐

有一台群晖的 NAS ,16TB RAID1 和 8T Basic 日常比较依赖 Synology Drive 同步文件数据 年底会因为公事出国呆一年多,想带着一些数据一起走 把这个 NAS 搬过去不现实,所以打算年中组一台全闪的移动 NAS 也考虑过对拷的那种移动硬盘盒(两个 M2 的那种) 想问有没有什比较好的解决方案?

作者: CLOUDUH | 发布时间: 2026-01-23 02:40


19. 有些 roundcube 主题的吗?

报个价, 留个联系方式.

作者: Hermitist | 发布时间: 2026-01-23 09:22


20. 小公司开发有什么需要避免的操作吗

目前背景: 是个小公司的后端开发,服务器,数据库,git,公司路由器都在我手里,感觉责任重大,想知道有什么需要避免的操作吗,主要是害怕万一一周或者几个月我不在,避免公司业务出问题

以下是我自己想到的几点,想知道还有没有其他没想到的方案

1.数据库的分区表,特别是和时间相关的,不能手动生成,要不然后面人不在没交代的话会直接给服务器崩掉

2.给本地调试的服务器端口白名单,不能图方便给网段开白名单,要不然后面会有脚本小子或者勒索病毒来扫

3.一些公共库,如果有不符合业务需求的地方,不要把人家的源码拉下来自己改然后编译成引用放在库里,(比如说 ef core upsert 的库之前不支持 ef10)否则后面更新时候会炸掉

4.单元测试不要埋雷,一些当调试用的或临时跑点小任务单元测试不能放在例行单元测试的文件夹里面,污染数据库

作者: yixin026 | 发布时间: 2026-01-22 06:51


21. all in vscode 远程开发体验 ssh 和 tunnel 对比.

  • 服务器远程开发, 服务器需要安装对应的 vscode 插件(只安装 code 分析, lsp 插件, 不安装 UI 插件, UI 插件本地装)
    • 端口自动转发, 你的代码中打印了 localhost:8080 端口, 会自动转发到本地
    • ssh 网络不好, 容易掉线, tunnel 肉眼可见的延迟, 好处就是无公网的机器也能直接远程

先上图

作者: SethShi | 发布时间: 2026-01-23 09:00


22. 死了么 APP 更新 2.0 版本变 Demumu:新增签到提醒、短信通知

目前,原“死了么”APP 在部分地区 App Store 上线 2.0 版本。更新记录显示,新版本新增签到提醒、短信通知,并修复若干问题。

值得注意的是,“死了么”APP 此前宣布要在新版本中正式启用全球化品牌名称“Demumu”,目前也已更名。

据介绍,该应用是为独居人群打造的轻量化安全工具。

用户需要设置紧急联系人并签到,若连续多日没在应用内签到,系统将于次日自动发送邮件告知紧急联系人。


6.99 刀,真的有人买么,我建议改成订阅制的🐶

作者: kiritoyui | 发布时间: 2026-01-23 01:23


23. vscode 怎么使用 claude

如题,现在美国梯子开了,vscode 以代理方式打开的,然后 claude 插件在验证后还是一直提示需要验证,请大佬指导下

作者: mr123villain | 发布时间: 2026-01-23 02:37


24. Antigravity 不能用 咋办?

使用 Antigravity Tools 能登陆到 Antigravity ,但是输入提示词,报错是什么原因?

LLMs aren’t perfect. There are a number of reasons why an error can occur:

LLMs can generate incorrect responses that we cannot handle.
Sometimes errors are part of a model’s research and planning process. It may take a mistake or two to learn your computer environment, what files exist, what tools are available, and so on.
If you believe this is a bug, please file an issue. As always, you can use the thumbs up or thumbs down feedback mechanism to help improve our metrics.

作者: fuxintong | 发布时间: 2026-01-23 02:38


25. 使用闲鱼上的 AI CODE 共享号、三方账号时会不会导致信息泄露

PS:源码不值钱,本来就是抄来的。但是不想泄露跟公司有关的一些信息,比如 API 、数据库配置、密码(写在.env 文件里,没有记在环境变量)

作者: unt | 发布时间: 2026-01-23 02:25


26. 在 vscode 的 claude code 插件中能否使用 Google Antigravity 反代?

如题,请问大家,在 vscode 的 claude code 插件中能否使用 Google Antigravity 反代?

如何使用?

作者: sn0wdr1am | 发布时间: 2026-01-23 01:13


27. AgentSkills for AI Developers

大家好,我是 AgentSkills.to 的开发者。

在开发过程中,我发现为 Claude Code 、Cursor 或 Codex CLI 重复编写复杂的提示词非常耗时。为了解决这个问题,我构建了 AgentSkills.to —— 一个开源的“技能”市场,旨在让 AI Agent 真正具备生产力。 为什么值得一试?

即插即用: 拥有 3,700+ 项涵盖前端、后端及 DevOps 的生产级技能。

跨平台: 完美适配 Claude Code, Cursor, Codex CLI 和 Amp 。 开源共享: 你可以免费获取所有工作流,也可以在 GitHub 上贡献你的独家秘籍。 我们的目标是让大家不再浪费时间“重复造轮子”,而是通过社区验证的技能快速交付高质量代码。

欢迎体验: https://agentskills.to

作者: quiqa | 发布时间: 2026-01-22 23:41


28. 有没有微信文件传输助手的 App 或开源第三方工具?

https://szfilehelper.weixin.qq.com/

这个网页很简单, 就能传文字和文件, 不知道有没有人做了相关工具的?

如果没有微信这方面的工具, 大家都是怎么在不同手机和电脑上互传文件的?
听闻 apple 生态很方便, 可是我主要用 windows, 手机是一加和 iPhone.

之前本来是搞了几个微信号来互传, 现在 google voice 注册的微信号啥也没干就给封号了.
Edge 的 drop 也用了好一阵, 最近老是无响应, 也很不好用了.
邮件又稍微有点麻烦, 没好的办法的话就只能用邮件了.

作者: jqknono | 发布时间: 2026-01-22 12:58


29. token 不够用,大家是一个什么组合

Claude Code pro+ claude code+minimax token 不够用,

大家是一个什么组合,感觉 glm 模型有点垃圾,一个小问题给我修的乱起八糟,也不太想用。

作者: chenguangwei | 发布时间: 2026-01-21 07:03


30. [独立开发] 单机 Rust 如何抗住 10w+ 在线行情推送?告别 Redis/Kafka,聊聊我的“极简主义”架构

大家好,我是《交易学徒》的独立开发者。

最近在重构后端行情网关,目标是支撑 10w+ 同时在线用户。在技术选型时,很多“标准答案”是微服务、Redis 集群、Kafka 消息队列。但作为独立开发者,维护这一套重型架构的运维成本和心智负担太高了。

于是我反其道而行之,选择了一种“极致单机” 的方案:没有任何外挂组件( No Redis, No Kafka ),所有状态在进程内解决,纯 Rust 函数调用。

经过实战验证,这套架构不仅部署简单(就一个 Binary ),而且足够稳定。今天分享一下我是如何用 Rust 的特性“白嫖”性能的,欢迎 V 友们拍砖。

一、 核心理念:按需订阅,算一笔带宽的账 早期的 demo 喜欢大包大揽,客户端连上来就推 Top 20 币种。这在用户量大时是灾难。我的做法是“用户看哪里,就只推哪里”

客户端停留在 BTC/USDT 的 15 分钟 K 线界面,服务端就只建立这一个订阅关系。一旦切换,立马移除旧订阅。

算一笔账( Resource Cost ): 假设一个行情包 Payload 是 200 Bytes ,推送频率 5 次/秒。

全量推送(推 Top 20 ):10 万用户 x 20 个币种 x 200B x 5 = 2 GB/s (带宽直接破产)。

按需订阅(推 1 个):10 万用户 x 1 个币种 x 200B x 5 = 100 MB/s 。

结论: 简单的逻辑改变,带宽节省 95%,单机千兆网卡轻松抗住。

二、 列表行情:Polling + 边缘计算(白嫖 CF ) 对于“行情列表”这种一屏显示几十个数据的页面,建立长连接维护成本太高。 我采用了 1 秒轮询 + Cloudflare 边缘缓存 的策略。

策略: 设置 HTTP 响应头,让 CF Edge Cache TTL = 1 秒。

效果:10 万人同时刷新列表,99% 的流量被 CF 的全球节点挡住了,真正打到我源服务器 Rust 进程的 QPS 只有个位数。

收益: 既利用了 CDN 的带宽,又保护了单机后端。

三、 架构做减法:进程内通信替代中间件 这是我这次重构最大的感悟:单机并发足够高时,不需要 Redis 和 Kafka 。

替代 Redis: 使用 Rust 的 DashMap (Concurrent HashMap)。数据就在内存里,读写是纳秒级,没有网络 IO 开销,没有序列化/反序列化成本。

替代 Kafka: 使用 tokio::sync::broadcast 和 mpsc::channel 。

优势: 传统的“发布-订阅”为了解耦上了 MQ ,但在单机 Rust 里,一个 Arc 就能解决问题。部署时不需要操心 MQ 挂没挂,只要我的进程活着,消息系统就活着。

四、 信使模式 (Messenger Pattern) 与背压 在 Tokio 异步编程中,最忌讳 await 阻塞。 如果客户端网络卡顿(比如进电梯),socket.send().await 可能会阻塞,导致同个 Loop 下的心跳包处理被卡死,造成“假死”。

我的解法:

读写分离: 为每个连接 spawn 一个独立的 send_task ,通过 mpsc::channel(128) 通信。

严格背压 (Backpressure): 使用 try_send 。如果 Channel 满了(说明客户端来不及收),直接丢弃新行情。

理由: 实时行情旧数据无价值。这行代码是系统的“保命符”,防止慢客户端拖垮服务端内存( OOM )。

五、 极致性能:Zero-Copy (零拷贝) 在广播行情时,不要为 10 万个用户 copy 10 万份数据。

Rust // 内存中只有一份二进制 Payload let payload = Arc::new(Bytes::from(vec![…]));

// 10 万次分发只是增加了 10 万次引用计数( Reference Counting ) // 几乎没有任何内存分配开销 for client in clients { client.tx.try_send(payload.clone()); } 利用 Rust 的 Arc 和 Bytes ,让 CPU 缓存极其友好。 六、 扫地僧:资源清理 长运行的单机服务最怕内存泄漏。 当 socket 断开时,必须像外科手术一样精准清理:

从 DashMap 移除 Client 。

清理反向索引 subscriptions 。

如果某个 Topic 无人订阅,立即 drop 掉对应的 channel 发送端,停止上游数据生产。

总结 作为独立开发者,资源有限。这套“Rust 单机 + 无外挂组件” 的架构,让我用最低的成本(一台服务器)抗住了业务压力,而且睡得很安稳。

Simplicity is the ultimate sophistication.

🎁 V 友专属福利 软件名字叫 《交易学徒》,是一个辅助交易员复盘、模拟、练盘感的工具。前端也是我用 Flutter 写的( Rust + Flutter 真是全栈开发的绝配)。

官网下载: https://www.zgjiazu.top

Google Play: https://play.google.com/store/apps/details?id=com.zengkai.jyxtclient

回帖福利: 在本帖回复并附上 App 内的 ID (在‘我的页面’可以看到),我后台人肉送一个月 VIP 会员。

同时也欢迎大家在评论区提 Bug ,或者交流关于 Rust 后端与 Flutter 前端开发的坑!

作者: kai92zeng | 发布时间: 2026-01-22 07:46


31. vibe coding 真的会上瘾啊,停不下来!

另外我发现 Claude opus 在写页面样式上真的比 gemini pro 差了一个档次啊。

当然其他方面感觉都很强,让我肃然起敬的那种🫡

作者: Aaron01 | 发布时间: 2026-01-21 21:00


32. 想请教大家关于学习新知识时的思路或者说最佳实践

最近在看着 Spring AI 的官方文档来学习 Java 在 AI 这方面的东西,但是我遇到一个问题就是,经常遇到看不懂,或者写了同样的代码却跑不起来的问题。

我举个例子: Spring AI 的官方文档的 Reference/Chat Client API 或者 Reference/Prompts 里面已经写了很多示例代码了,但是其实跟着写出这些代码后,程序是跑不起来的,一直到下面第五节的 Models 篇章里面,才介绍了说需要引入各模型的依赖,上面那些章节的示例代码才能运行。

我觉得可能是我的文档阅读思路不对(或许应该先整体大致阅读一遍?然后再考虑写 demo 来熟悉?),所以想问问大家,大家在学东西的时候,一般是遵循怎样的学习思路来学习的?看书?看视频?或者说,大家阅读官方文档的时候,是怎样的思路来阅读的?

作者: AkaneWWW | 发布时间: 2026-01-22 14:30


33. giffgaff 手机卡充值后才有信号吗

闲鱼上买的一个卡,插上后一直无服务,必须充值以后才有信号吗?

20 多买的,发现论坛上还有免费送呢,亏大了

作者: yuanyao | 发布时间: 2026-01-22 05:29


34. 大家都是用什么 AI 来生成设计稿的?

比如我想要做一个 App ,代码是可以使用 Cursor 之类的 IDE 来做,但是整体看起来的 UI 效果不是很好,有没有可以生成 UI 设计稿,或者生成一些图标的?或者大家自己独立做开发的时候,如何解决 UI 这块的需求。

希望各位大佬帮忙解答下,先提前谢谢了~

作者: canyu9512 | 发布时间: 2026-01-22 08:56


35. 国内外一个有趣的技术倾向区别

今天在看分布式任务工具 找来找去看到 3 个,xxl-job, powerjob, elasticjob 然后我发现居然全是国产的,类似产品竟然没有国外的,我寻思不应该啊 (不是说国外的就好什么的,但是这种中间件没有的话确实感到奇怪) 问了 AI 得到如下回答

XXL-JOB 、ElasticJob 这类工具在中国特别火,是由中国互联网特定的技术土壤决定的

国外用 Quartz ,它是祖师爷,国内工具大多是对 Quartz 的二次封装(加了 UI 、加了分片、加了 RPC )。国外老项目仍大量直接用 Quartz 。

国外云原生走得更早,很多简单的定时任务直接交给 Kubernetes CronJob 或云厂商的 Serverless 服务了,不需要额外部署一个 XXL-JOB ,复杂的任务则是选择 Airflow 这样的工作流平台

国内的 ElasticJob 和 XXL-JOB 实际上是卡在了“简单 Cron”和“复杂编排”中间的一个完美生态位:它比 Quartz 好用,比 Airflow 简单,又完美契合 Java 生态

如果真是这样那感觉还是挺有意思的,居然这样奇怪的产生了一个技术生态位

作者: litchinn | 发布时间: 2026-01-22 06:40


36. AWS 实例无法 ping 通求助

我在 AWS 上的的实例,公网 ip54.183.16.48 ,无法访问,ping 不通。 在终端运行 curl icanhazip.com ,确定 IP 是 54.183.16.48 无误。 检查了安全组,开通了 22 80 443 端口,源 ip 0.0.0.0/0, 在终端 ping54.183.16.48 也 ping 不通 可是在其网页端可以登录实例 求助

作者: hwhtj | 发布时间: 2026-01-23 01:30


37. Antigravity 反重力挂了,但 Antigravity Tools 反代出来的 API 还能用

那可以用 Claude Code + Opus4.5 继续干活了?

不,该下班了。

作者: imik | 发布时间: 2026-01-22 09:47


38. 微软免费 2 年的 Microsoft 365 Premium 订阅—继上次免费 e3 全局

继上次微软免费的 Microsoft 365 E3 全局 https://v2ex.com/t/1172827

看到隔壁有人发,我想起了去年也验证过,方法很简单,当然前提你有 edu 邮箱,没有的话去 google 搜个社区大学注册。

去年起微软针对教育用户(学生)免费提供 2 年的 Microsoft 365 Premium 订阅。按微软价格的话,大概人民币 3000 多。

Microsoft 365 Premium 以每月 19.99 美元的价格,同时提供微软 Office 套件的使用权限与 Copilot Pro 的功能。该订阅包含更高的功能使用限额,以及 Copilot Labs 、Actions 等 Copilot Pro 专属功能的访问权限等。同时你可以通过电子邮件邀请最多 5 个人加入你的 Microsoft 365 家庭版订阅。

截图

具体方法

必备条件 edu 邮箱。 邮箱

登录你的微软个人账号,依次点击下面链接,进入验证,填写你的大学 edu 邮箱。 邮箱 个人版: https://checkout.microsoft365.com/acquire/purchase?language=EN-US&market=HK&requestedDuration=Month&scenario=microsoft-365-student&client=poc&campaign=StudentFree12M

高级版: https://checkout.microsoft365.com/acquire/purchase?language=EN-US&market=HK&requestedDuration=Month&scenario=microsoft-365-premium&client=poc&campaign=StudentPremiumFree12M 我的订阅

支付方式支持 paypal ,支付宝等,验证订阅后,你可以直接取消自动续费,就不会扣费风险!

作者: tunggt | 发布时间: 2026-01-20 04:16


39. 请问抖音,学浪的视频课,有办法下载么?

现在是在抖音里看,
想保存只能录屏么?有高手下载过么?

作者: mrlfishman | 发布时间: 2026-01-22 10:49


40. [踩坑] A 股开盘把 Python 搞挂了,怒切 Go 重写行情网关 (附 pprof 分析 + 源码)

💥 事故现场
LZ 所在的量化小厂,早期基础设施全是 Python (Asyncio) 一把梭。 跑美股( US )的时候相安无事,毕竟 Tick 流是均匀的。 上周策略组说要加 A 股 (CN) 和 外汇 (FX) 做宏观对冲,我就按老套路接了数据源。

结果上线第一天 9:30 就炸了。 监控报警 CPU 100%,接着就是 TCP Recv-Q 堆积,最后直接断连。 策略端收到行情的时候,黄花菜都凉了(延迟 > 500ms )。

🔍 排查过程 (Post-Mortem)
被 Leader 骂完后,挂了 py-spy 看火焰图,发现两个大坑:

Snapshot 脉冲:A 股跟美股不一样,它是 3 秒一次的全市场快照。几千只股票的数据在同一毫秒涌进来,瞬间流量是平时的几十倍。

GIL + GC 混合双打:

json.loads 是 CPU 密集型,把 GIL 锁死了,网络线程根本抢不到 CPU 读数据。

短时间生成大量 dict 对象,触发 Python 频繁 GC ,Stop-the-world 。

🛠️ 架构重构 (Python -> Go)
为了保住饭碗,连夜决定把 Feed Handler 层剥离出来用 Go 重写。 目标很明确:扛住 A 股脉冲,把数据洗干净,再喂给 Python 策略。

架构逻辑:WebSocket (Unified API) -> Go Channel (Buffer) -> Worker Pool (Sonic Decode) -> Shm/ZMQ

为什么用 Go ?

Goroutine:几 KB 开销,随开随用。

Channel:天然的队列,做 Buffer 抗脉冲神器。

Sonic:字节开源的 JSON 库,带 SIMD 加速,比标准库快 2-3 倍(这个是关键)。

💻 Show me the code
为了解决 协议异构( A 股 CTP 、美股 FIX 、外汇 MT4 ),我接了个聚合源( TickDB ),把全市场数据洗成了统一的 JSON 。这样 Go 这边只用维护一个 Struct 。

以下是脱敏后的核心代码,复制可跑(需 go get 依赖)。
package main

import (
“fmt”
“log”
“runtime”
“time”

github.com/bytedance/sonic“ // 字节的库,解析速度吊打 encoding/json
github.com/gorilla/websocket
)

// 防爬虫/防风控,URL 拆一下
const (
Host = “api.tickdb.ai
Path = “/v1/realtime”
// Key 是薅的试用版,大家拿去压测没问题
Key = “?api_key=YOUR_V2EX_KEY”
)

// 内存对齐优化:把同类型字段放一起
type MarketTick struct {
Cmd string json:"cmd"
Data struct {
Symbol string json:"symbol"
LastPrice string json:"last_price" // 价格统一 string ,下游处理精度
Volume string json:"volume_24h"
Timestamp int64 json:"timestamp" // 8 byte
Market string json:"market" // CN/US/HK/FX
} json:"data"
}

func main() {
// 1. 跑满多核,别浪费 AWS 的 CPU
runtime.GOMAXPROCS(runtime.NumCPU())

url := “wss://“ + Host + Path + Key
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
log.Fatal(“Dial err:”, err)
}
defer conn.Close()

// 2. 订阅指令
// 重点测试:A 股(脉冲) + 贵金属(高频) + 美股/港股
subMsg := { "cmd": "subscribe", "data": { "channel": "ticker", "symbols": [ "[600519.SH](http://600519.SH)", "[000001.SZ](http://000001.SZ)", // A 股:茅台、平安 (9:30 压力源) "XAUUSD", "USDJPY", // 外汇:黄金、日元 (高频源) "[NVDA.US](http://NVDA.US)", "[AAPL.US](http://AAPL.US)", // 美股:英伟达 "[00700.HK](http://00700.HK)", "[09988.HK](http://09988.HK)", // 港股:腾讯 "BTCUSDT" // Crypto:拿来跑 7x24h 稳定性的 ] } }
if err := conn.WriteMessage(websocket.TextMessage, []byte(subMsg)); err != nil {
log.Fatal(“Sub err:”, err)
}
fmt.Println(“>>> Go Engine Started…”)

// 3. Ring Buffer
// 关键点:8192 的缓冲,专门为了吃下 A 股的瞬间脉冲
dataChan := make(chan []byte, 8192)

// 4. Worker Pool
// 经验值:CPU 核数 * 2
workerNum := runtime.NumCPU() * 2
for i := 0; i < workerNum; i++ {
go worker(i, dataChan)
}

// 5. Producer Loop (IO Bound)
// 只管读,读到就扔 Channel ,绝对不阻塞
for {
_, msg, err := conn.ReadMessage()
if err != nil {
log.Println(“Read err:”, err)
break
}
dataChan <- msg
}
}

// Consumer (CPU Bound)
func worker(id int, ch <-chan []byte) {
var tick MarketTick
for msg := range ch {
// 用 Sonic 解析,性能起飞
if err := sonic.Unmarshal(msg, &tick); err != nil {
continue
}

if tick.Cmd == “ticker” {
// 简单的监控:全链路延迟
latency := time.Now().UnixMilli() - tick.Data.Timestamp

// 抽样打印
if id == 0 {
fmt.Printf(“[%s] %-8s | Price: %s | Lat: %d ms\n”,
tick.Data.Market, tick.Data.Symbol, tick.Data.LastPrice, latency)
}
}
}
}

📊 Benchmark (实测数据)
环境:AWS c5.xlarge (4C 8G),订阅 500 个活跃 Symbol 。 复现了 9:30 A 股开盘 + 非农数据公布 的混合场景。
指标,Python (Asyncio),Go (Sonic + Channel),评价
P99 Latency,480ms+,< 4ms,简直是降维打击
Max Jitter,1.2s (GC Stop),15ms,终于不丢包了
CPU Usage,98% (单核打满),18% (多核均衡),机器都不怎么转
Mem,800MB,60MB,省下来的内存可以多跑个回测

📝 几点心得
术业有专攻:Python 做策略逻辑开发是无敌的,但这种 I/O + CPU 混合密集型的接入层,还是交给 Go/Rust 吧,别头铁。

别造轮子:之前想自己写 CTP 和 FIX 的解析器,写了一周只想跑路。后来切到 TickDB 这种 Unified API ,把脏活外包出去,瞬间清爽了。

Sonic 是神器:如果你的 Go 程序瓶颈在 JSON ,无脑换 bytedance/sonic ,立竿见影。

代码大家随便拿去改,希望能帮到同样被 Python 延迟折磨的兄弟。 (Key 是试用版的,别拿去跑大资金实盘哈,被限流了别找我)

作者: Howiee | 发布时间: 2026-01-21 08:22


41. 公司营销被运营商截胡,有什么好办法吗

有新用户注册后,很快就会有人给新用户打电话,然后推荐其他家的产品。

老板在测试自家产品的时候,用新手机号注册,过了大概五分钟就有人给他打电话售卖其他产品。

公司很小,没有什么内部卖数据的必要性。所以怀疑是运营商把数据卖了(听说运营商确实卖这类数据),但是并没办法实锤。

各位 V 友们,有什么好办法吗?

作者: DendimoN | 发布时间: 2026-01-22 02:38


42. antigravity 挂了,只能开始“古法手作”了

作者: bingqilinphenjh | 发布时间: 2026-01-22 09:59


43. 今天 TUN 模式也连不上 Angravity 了

之前还好好,今天突然 load 不出 model 了,有佬提供下终极方案吗

作者: nomisk | 发布时间: 2026-01-22 10:00


44. 如果充会员,你们会选择哪一家 AI?

之前微软勾引咱,给咱免费使用 Github Copilot Pro 。 现在微软收回去了,咱在 Google Antigravity 流浪。

现在总感觉额度不够用,想冲会员。

如果充会员的话,你会选 vscode 的 Github Copilot ,还是 antigravity 的 google 会员?

PS:antigravity 在 arm 服务器上用不了 remote ssh ,旧一点的 CPU 电脑上也用不了 remote ssh 。vscode 可以。

总是听说 Claude 系列编程给力,但是无奈我每次用 Google Antigravity 体验 Claude ,嗖的一下额度就没了。冲会员额度能管够吗

作者: sn0wdr1am | 发布时间: 2026-01-21 01:09


45. 免费 chat app 哪家强

我主力开发工具是 cursor ,为了节省用量,我一般会在 chat app 里先脑暴一下,或者做一些数据处理

我使用过的 chat 不算多,chatgpt claude grok deepseek ,而且都没有付费过,所以不太清楚上限

但目前我基本只用 grok 了,有几个原因
- grok 免费用量挺多的,基本不会用超,其他几个很容易用超
- 我最看重的是联网查询能力,可以帮我搜一些新的文章、项目等,grok 基本每次都能搜 20-50 个引用,在用过的 app 里面算挺多的了
- grok 的输出风格比较适中,chatgpt 会使用太多的 list
- grok 审查比较宽松

我的使用场景其实比较有限,想知道大家都是怎么搭配用的,免费和收费的工具都有哪些推荐

作者: Cyron | 发布时间: 2026-01-22 05:37


46. 站长们注意了,网站必须要有 robots.txt

如果网站的根目录没有 robots.txt 文件,谷歌搜索就不会索引其内容,或者之前有但后来删除了,谷歌便会从其索引里删除该网站的所有搜索结果。 https://www.alanwsmith.com/en/37/wa/jz/s1/

作者: zf9617 | 发布时间: 2026-01-23 03:36


47. edge 和系统的绑定是真的恶心啊

最近开发总是浏览器和 moba 终端来回切换,每次都自动变成中文,原本以为是系统的 bug,最近有时间试了一下,真的只有 edge 切换到其它界面才会保留输入法状态,也就是说,edge 是中文的,你切换到其它界面肯定也是中文,不管你原先的界面是什么,真心被恶心到了

作者: son012 | 发布时间: 2026-01-22 06:03


48. flutter 生态这么差?写个 demo 两天都没调通

用 vlc 插件写个播放器 android linux 没一个能正常播放出画面。报什么通道创建错误。不管本地,网络流都报一个错。

这生态环境太恶劣了吧。ai ,google 都不能解决问题

实在是太难搞了

作者: wnpllrzodiac | 发布时间: 2026-01-21 10:25


49. 对 llm 的感性化感叹:师者,传道授业解惑也。

在我的个人求学生涯和 1.5 年的职业生涯中,目前 llm 对我在专业上的帮助是最大的。

虽然它也会胡说八道,但是它是真的耐心教我,有求必应,竭尽所能,没有主观上的耍我坑我利用我。

有条件的朋友,真建议试试最顶尖的模型,和这些模型交流的体验真的是,比跟那些谄上欺下
的,自视甚高的,彼此防备的,勾心斗角的,一团浆糊的,不可理喻的愚蠢的人类要强的多。

当然了,llm 的背后包括架构和数据,是来自于广泛的人类的智慧, 这一点不可忽视。虽然,人个体其实也是广泛的人类的智慧的训练结果,没差异。

作者: YanSeven | 发布时间: 2026-01-22 03:01


50. Nature 编程语言集成 WebView

一位开发者尝试在 nature 编程语言 中集成 WebView (项目地址:https://github.com/wzzc-dev/nature-webview),采用类似 Rust Tauri 的集成方式,最终打包完成后可以得到体积小巧、轻量化的可执行桌面程序。

这个简单的桌面程序就是由 nature + webview 打包而来,在 macos arm64 上只有 680KB 的大小,下面是一个更加简单的 hello world 代码示例

import webview as w
import webview.{webview_t}
import libc.{cstr, to_cfn}
import co.{sleep}
import co
import runtime

fn interval_callback() {
    co.yield() // Yield coroutine every 10ms to allow GC to run
}

fn other() {
    for true {
        println('other co')
        sleep(1000)
    }
}

fn main() {
    println("Hello, Nature Webview!")

    @async(other(), co.SAME)

    var window = w.create(1, null)
    w.set_title(window, "Hello World".to_cstr())
    w.bind(window, "interval_callback".to_cstr(), to_cfn(interval_callback as anyptr), 0)

    var html = `
      <html>
          <body>
              <script>setInterval(() => {window.interval_callback();}, 10);</script>
              <h1>Hello, Nature!</h1>
          </body>
      </html>`

    w.set_html(window, html.to_cstr())

    w.run(window) // blocking coroutine!
    w.destroy(window)
}

nature 是一款基于全局协程模型的编程语言,它与 WebView 的兼容性并不理想。起初该方案完全无法运行,nature-webview 的作者与我进行了沟通, 我认为这是一项非常有意义的工作,是 nature 核心 GUI 特性的重要环节,因此我着手排查并解决导致运行失败的问题,经过一个周末努力,主要问题都被解决,我迫不及待的将其分享出来!

WebView 必须运行在 t0 系统栈 + 系统线程中

在 macOS 系统上,编译完成后程序虽能正常启动,但通过 JS 回调 nature 时却发生了崩溃,且这个崩溃的调用栈非常深,难以追溯。即便通过 Debug 方式构建 WebView ,依旧无法获取完整的调用栈。

最终发现这是因为 WebView 动态依赖 WebKit 库,而 WebKit 库无法追踪调用栈 。经过多次尝试后偶然发现了 macos 的崩溃报告,我发现其中包含了完整的堆栈追踪日志!原来我一直忽略了如此重要的信息。

命令行执行程序崩溃时,也可以通过 ~/Library/Logs/DiagnosticReports/ 直接查看堆栈追踪日志

Crashed Thread:        0  Dispatch queue: com.apple.main-thread
Exception Type:        EXC_BREAKPOINT (SIGTRAP)

Termination Reason:    Namespace SIGNAL, Code 5 Trace/BPT trap: 5
Terminating Process:   exc handler [37708]

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   JavaScriptCore                	    0x7ff828e4b7d1 JSC::LocalAllocator::allocate(JSC::Heap&, JSC::GCDeferralContext*, JSC::AllocationFailureMode)::'lambda'()::operator()() const + 6801
1   JavaScriptCore                	    0x7ff829574b24 JSC::VM::VM(JSC::VM::VMType, JSC::HeapType, WTF::RunLoop*, bool*) + 24452

根据日志可以判断这是一个通过类似 assert 抛出来的断点类型的异常,并且发生在内存分配中,说明这极有可能和运行环境相关。

于是我尝试使用 C + WebView 进行对比测试并复现问题,nature 是运行在协程和协程栈中,所以通过 c 库的 mcontext + mmap stack 模拟 nature 的运行模式,果然重现了错误。到这里已经大概猜测是 WebKit 会进行运行时栈检测,并且是通过 pthread_get_stackaddr_np 的方式直接读取线程默认栈。

这是一个棘手的问题,如果需要兼容 WebView 需要对 nature 的基础架构进行一定改动。到目前为止都还只是猜测,为了证实测测我去下载了一个多 G 的 WebKit 代码定位堆栈追踪中的函数。最终定位到了下面的关键逻辑

ALWAYS_INLINE void* LocalAllocator::allocate(JSC::Heap& heap, size_t cellSize, GCDeferralContext* deferralContext, AllocationFailureMode failureMode)
{
    VM& vm = heap.vm();
    if constexpr (validateDFGDoesGC)
        vm.verifyCanGC();
    return m_freeList.allocateWithCellSize(
        [&]() ALWAYS_INLINE_LAMBDA {
            sanitizeStackForVM(vm);
            return static_cast<HeapCell*>(allocateSlowCase(heap, cellSize, deferralContext, failureMode));
        }, cellSize);
}

这个函数的结构和堆栈追踪中显示的一致,虽然有版本变动带来的影响,但是大概率就是该函数导致了崩溃,进一步追踪发现其中的 sanitizeStackForVM 函数果然使用了 pthread_get_stackaddr_np 来获取栈信息并进行 assert 判断。

问题到这里基本已经确定,可以尝试解决该问题。过去我知道 UI 必须在系统默认线程上渲染,但是没想到有些 UI 库对栈的要求也如此严格。由于 nature 的协程运行在共享栈中,所以解决起来也比较简单,直接拿系统栈作为共享栈使用即可,不过系统栈还需要驱动 procesor 运行,所以我暂时拿其中一半系统栈来作为协程的共享栈。

当然这是一个临时解决方案,在较新的 macos 26.2 系统中并不会发生类似的崩溃,以后也许可以继续使用 mmap 进行栈分配。

WebView 必须使用 glibc

由于 macos 系统发行版本单一,并且强制要求使用动态库链接,所以 nature 在 macos 上没有遇到编译问题,但是在 linux 上则出现了该问题。

nature 在 linux 系统上基于 musl 进行纯静态编译,libruntime.a + libuv.a + libc.a 是 nature 依赖的核心,这三件套都是 musl libc 纯静态编译的,所以跨平台性很好,一次编译到处运行。

WebView 在 linux 上依赖的 webkit 和 gtk 必须基于 glibc 动态编译 ,这和 nature 现在的编译理念产生了严重的冲突。动态编译的 webkit 和 gtk 在不同的 linux 发行版本上也有着兼容问题。难道这无法解决么?还真不行,Rust 的 tarui 在 linux 系统上也同样有着这样的兼容困扰。

既然现在 webkit 和 gtk 直接打破了静态编译的幻想,必须动态编译,必须依赖 glibc ,牺牲一定的跨平台性,那 nature 索性直接放弃静态编译和交叉编译的思路,直接使用 glibc 进行动态编译好了。

使用系统自带的链接器 ld 将 nature 依赖的静态库代码和 webkit 相关库进行动静态库混合链接后,终于在 ubuntu 22.04 desktop 上运行成功。

nature 手写的链接器只实现了静态编译部分,所以动态编译时需要通过 –ld /usr/local/ld 指定系统链接器。

为了更好的兼容性 nature build 的 –ldflags 参数还需要进行调整,在识别到传递 -lc 参数后,会自动去掉 libc.a 的依赖。有一个比较神奇的地方在于 musl libc 工具链编译的 libruntime.a 和 libuv.a 能够和 glibc 库直接混合链接使用。

最终得到的令人眼花缭乱的编译参数 😄,nature 并不依赖于 gcc 工具链,所以需要在 ldflags 中处理 crtendS 这样的初始化文件。

nature build --ld '/usr/bin/ld' --ldflags "/usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o /usr/lib/gcc/x86_64-linux-gnu/11/crtendS.o --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/11 --whole-archive /usr/local/lib/libwebview.a --no-whole-archive -lwebkit2gtk-4.1 -lgtk-3 -lgdk-3 -lz -lpangocairo-1.0 -lcairo-gobject -lgdk_pixbuf-2.0 -latk-1.0 -lpango-1.0 -lcairo -lharfbuzz -lsoup-3.0 -lgio-2.0 -lgmodule-2.0 -ljavascriptcoregtk-4.1 -lgobject-2.0 -lglib-2.0 -lstdc++ -lgcc_s -lpthread -lc" test.n --verbose

w.run 阻塞 runtime

现在解决所有的问题了么?注意看这一行代码,它直接指向了一个 c++ 函数 webview_run ,并且这个函数永远不会返回。这会发生什么?

w.run(window) // blocking coroutine!

经过上面的适配,webview 成功在协程中运行,如果你足够了解协程的运行原理,你就会知道这一行阻塞操作会占用核心线程都控制权,这导致在该核心线程上的协程调度器和其他协程永远都不会运行。但这还不够致命,nature 可以轻易的通过创建新的线程来解决这个问题。真正的问题是阻塞系统调用会导致该线程无法进入 STW 状态,从而阻塞整个 GC ,这才是真正无解且致命的问题。

nature 采用了协作式的调度方案,意味着更多的控制权交在了开发者手上,为了更友好的 GUI 体验,也许应该尝试一些不同的方案。于是最终使用了一个比较 hack 的方式解决了该问题。

w.bind(window, "interval_callback".to_cstr(), to_cfn(co.yield as anyptr), 0)

var html = `
  <html>
      <body>
          <script>setInterval(() => {window.interval_callback();}, 10);</script>
          <h1>Hello, Nature!</h1>
      </body>
  </html>`

我们在 js 代码中创建了一个定时器,每 10ms 调用一次 nature 函数绑定,该函数绑定会 yield 当前协程将控制权交还给协程调度器。 通过这种方式不需要调整任何的 nature 编译器让整个协程调度器能够正常运转,代价大概就是需要 10ms 的延迟,而不是按需调度罢了。但是至少不会产生 GC 问题。

C/C++ 回调 nature fn

C/C++ 是不安全非托管的函数能够回调 nature 函数吗?原则上不行,比如 golang 不允许,因为 golang 的 C 代码和 go 代码运行在了不同的栈中,所以无法直接调用。

nature 和 C 代码在同一个共享栈中运行 ,所以回调能够正常触发。但在当前的设计中,nature 没有考虑过作为回调被 C 代码调用,所以 GC 不能正确的识别该混合调用模式。但这还算好解决,我们可以通过追溯栈帧获取整个栈上的函数调用链条并进行 GC root mark, C 在大多数情况下同样遵循该栈帧规则。

另外一个问题是闭包问题

fn foo() {}

fn main() {
    int a = 1
    fn() f = foo
    f = fn() {
        var b = a // Reference to external var
    }
    
    f()
    foo()

}

在高级编程语言中通常会区分闭包和全局函数,在上面的代码示例中,面对一个 fn 类型的变量 f ,编译器无法追踪其是全局函数还是闭包。所以通常会采取妥协的策略将 fn 类型变量统一按照闭包进行存储和使用。如图,fn 并不是一个单独的指针指向函数的地址,而是一个 16byte 的 pair 结构。

所以如果直接将 nature 中的 global fn 通过参数进行传递时,该参数是一个 16byte 的奇怪数据,C 并不知道 fn 的地址是什么,所以还需要从闭包中提取 fn 地址传递给 C 。这里的 libc.to_cfn 做了一个简单的工作,就是直接抛弃 env ptr(全局函数的 env ptr 总是为 null)并从中提取 fn ptr 传递给 C 函数。

w.bind(window, "interval_callback".to_cstr(), libc.to_cfn(interval_callback as anyptr), 0)

总结

到这里已知的问题都得到了解决,虽然方案上比较妥协,但是最终还是让 nature 编程语言成功集成了 WebView ,并且能够达到和 C + webview 一样的原生性能体验,同时也能够享受 GC 编程语言带来的安全性和协程的便利性。而 WebView 是一个典型的 C/C++ UI 库的示例,可以采用同样的方式集成类似 sokol/ImGui 等 UI 库。

https://nature-lang.cn/news/20260115 就如上一篇文章最后提到的,可控内存分配器和 unsafe 裸函数支持是原本的 GUI 支持策略基础,但是未料到共享栈模式的协程和 C/C++ 的兼容性如此优秀,直接就完成了适配。不过这种妥协不会是最终的解决方案,unsafe 裸函数和可控内存分配模式的工作会继续推动。到时候 nautre 的 main 函数可以选择独立于协程调度系统采取单独的线程和栈运行,让 nature 更加适应原生的 GUI 开发。

当然图形化操作系统 windows 同样是 GUI 支持重要一个环节,我将会进行看进行支持,由于调整了 nature 的源码,所以需要等到 0.7.3 版本发布时才能体验 nature-webview ,在这期间我会使用 nature 结合 webview 开发一个小项目进一步测试可用性。

作者: weiwenhao | 发布时间: 2026-01-22 09:06