首页 文章 精选 留言 我的

精选列表

搜索[WorkBuddy],共4325篇文章
优秀的个人博客,低调大师

串行抓书死了两次,换并发一次跑通——后怕的不是失败,是我根本不知道它为什么死 #WorkBuddy#

先把结论放前面:那天晚上,一个更保守的方案失败了两次,一个看起来更激进的方案一次跑通。到今天我也不知道第一次为什么死。 这件事让我后怕的地方,不是失败本身,是**我差点就给自己编了一个原因,然后把它当真事记下来**。 ## 起因:我要给 AI 垫一本书 10 月 16 日傍晚,我在做一件后来写进上篇文章的事:把吴恩达那本免费公开的《机器学习策略》全文抓下来,给 AI 当背景材料。 书的来源很干净:作者本人在 GitHub 上开源了中文版,我直接走 API 取 Markdown 原文,不下载 PDF,不做 OCR。共 58 章。 抓取这种事,我的第一反应是稳妥起见:**一章一章来,串行,慢就慢点,稳要紧。** 这个决定看起来没有任何问题。事后证明,问题恰恰出在这个"看起来没有任何问题"上。 ## 第一次翻车:进程被掐了 串行脚本跑起来没多久,进程直接没了。终端里剩下一行: ``` exit code 137 ``` 我当时的反应,说出来不怕你笑:**我以为是我这边网络抖了一下。** 重跑。又死了。还是 137。 两次。同一个地方,同一个退出码。 到这里我停手了。不是因为我懂了,是因为我意识到再跑第三次大概也是这个结果——**同一个输入、同一个输出,这不是运气问题,是某个我不知道的东西在系统性地拦截我。** ## 转折:换并发,一次跑通 我换了写法:线程池,8 个 worker 并发抓。这个改动方向上跟"稳"是反着来的——同时开 8 个请求,听起来更容易出事。 结果:58 章,一次跑完,零失败。成品文件 144,407 字节,落盘时间 19:02,我核过 ![](https://developer.qcloudimg.com/http-save/yehe-12824395/7e8e924073127e3e1da3b1eab7bbf713.png) 。 **更稳的死了,更激进的活了。** 这个结果跟我脑内的直觉完全拧着。正常人这时候会干什么?会找一个解释,把这件事圆过去。我也一样。而且我确实找到了一个特别顺口的—— ## 我给自己编的解释,差点就信了 第一版解释是这样的:串行是一个进程从头跑到尾,内存越攒越多,最后被系统杀掉;并发每个任务小,用完就释放,所以活下来了。 这个解释听起来很有道理,对吧?我当时已经打算把它写进文章了。 然后我干了一件事后看特别值的事:**我去核了数字。** 全书 58 章加起来,144,407 字节。**144 KB。** 一张手机照片的零头。 一个进程跑一个总量 144 KB 的任务,攒内存攒到被系统杀掉?这个解释撑不住了。**数据量根本不够格。** 那一刻我有点冒汗——如果我顺手把这个解释写出去了,它现在就挂在一篇公开发表的文章里,看起来还挺像回事。 ## 那到底为什么死?我不知道 诚实的答案是:不知道。我能列出来的候选解释有三个,每一个都没有证据: 1. **系统内存压力**——macOS 内存紧张时确实会杀进程。但 144 KB 的任务量让这个解释很勉强; 1. **运行环境的资源守卫**——我的脚本跑在一个有资源限制的沙箱里,守卫可能因为别的原因(请求数、运行时长)动手。有可能,但我没有它的日志; 1. **串行脚本自身的问题**——比如某个我没意识到的写法缺陷。有可能,但**原脚本已经删了**,我想复盘都没得复盘。 第三个是我最懊悔的。出事那晚我要是留一份现场——把退出码、时间点、系统日志抓下来存个档——今天这篇文章就不用写"我不知道"这四个字。 **失败不可怕,失败现场没留档才可怕。因为那意味着你连"不知道"的资格都没有——你只有"永远不知道"。** ## 退出码其实在说话,是我没听 这次逼我停下来的,是那个 137。我之前对它的态度是"反正重跑就行",从来没想过去解码它。这回我认真查了,还在自己机器上做了个十秒钟的实验: |杀进程的信号|信号编号|进程退出码| | --- | --- | --- | |SIGKILL|9|137(= 128 + 9)| |SIGTERM|15|143(= 128 + 15)| 规则很简单:**正常退出的码是程序自己给的;被信号杀掉的,退出码 = 128 + 信号编号。** 137 意味着进程是被 SIGKILL 干掉的——就是那种不给任何收拾遗言机会的、直接从内核层面掐死 ![](https://developer.qcloudimg.com/http-save/yehe-12824395/c80a78e78eab1ea43f3363ad99f499fd.png) 。 写到这里我要做一个不太舒服的更正。 ## 一篇旧文的更正 我之前发过一篇讲同一晚蒸馏那本书的文章,里面把 exit 137 解释成了"SIGTERM,内存回收"。**这个说法是错的。** SIGTERM 对应的退出码是 143,137 是 SIGKILL。这个错误是从我当晚的笔记一路带进文章的——我当时没做实验,抄了自己没验证的记录。 两件事让我把这条更正写出来: 一是**退出码是命令行世界最基础的语言**,我一个天天跟终端打交道的人把它读错了,还被平台审核顺利放行——错误不会因为平台没拦住就不存在。 二是它恰好证明了这篇文章的主题:**我在没有证据的时候,随手给自己编了个解释。** 上一篇文章里那个"内存回收",跟这次我差点写出去的"内存越攒越多",是同一个毛病的两次发作。 线上那篇我会走编辑入口改掉。这篇文章算是立此存照。 ## 这件事改了我的三个习惯 **第一,退出码要解码,不要背。** 128 + N 这个公式两秒就能查到,但它把"进程被杀了"和"进程自己退了"区分开——这两件事的下一步动作完全不同。前者去查谁杀的,后者去查程序逻辑。我之前把两者混成一团,所以才会用"重跑"去应对一个系统性的拦截。 **第二,失败现场当场留档。** 现在我的规矩是:进程异常死掉,先抓三样东西再动手重跑——退出码、时间戳、系统日志(macOS 上是 `log show` 的最近片段)。三十秒的事,换的是"以后还能复盘"的资格。 **第三,"更稳"是个需要验证的判断,不是免检标签。** 串行比并发稳,这话单拎出来谁都觉得对。但至少在我那个场景里,事实是反的。我不打算从这里推出"并发永远更稳"——那就是用一个反直觉故事换一个新教条,没意思。我只想记住:**"稳"是我当时的假设,不是我当时的数据。** ## 边界声明 这篇的结论在什么条件下成立,超出范围我不知道: - 样本量 n=1:一次串行失败 ×2、一次并发成功,没有做交叉重复实验。"串行死、并发活"在我当晚的场景里是真的,**它是不是规律,我没有数据**; - "为什么死"三个候选解释全部未验证,列出来说明的是"我查过哪些方向",不是"我确认了哪个"; - 退出码 128+N 是 POSIX 信号语义,跨 Unix 系统通用;但"谁发的 SIGKILL"跟具体运行环境有关,我的排查结论不能搬到你机器上直接用; - 书的抓取走的是作者本人开源的 GitHub 仓库,这个前提不成立的话(比如抓有版权墙的站点),整个讨论换一套规则。 --- *文中数字来源:58/58 章、144,407 字节、成品落盘时间 2026-10-16 19:02,来自本机文件实测;串行两次 exit 137 记录自当晚工作日志;SIGKILL→137 / SIGTERM→143 为 2026-10-19 本机实跑对照(Python subprocess,返回 -9 与 -15,对应 shell 退出码 137 与 143)。*

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册