Python进阶与并发编程06:让三个HTTP等待重叠,线程池到底管理什么
Python进阶与并发编程06让三个HTTP等待重叠线程池到底管理什么第05课的程序能够在一家供应商失败时保留其他结果但它仍然逐个等待。atlas返回之前boreal连请求都没有发出去。对于这种大部分时间花在网络等待上的任务我们可以让多个线程分别等待主线程收集完成的结果。业务公式、协议校验和最低价规则不需要改变。本课要解决的不是“把for循环换一个库”这么简单的问题。请求完成的顺序开始不稳定多个工作者可能修改同一个计数器调用方超时后线程可能仍在运行。只有同时理解这些行为线程池才是资源管理工具而不只是看起来更快的语法。E05完整答案把失败边界放在每个供应商周围上一课E05原题是broken场景、购买1件boreal503时保留atlas与cedar失败列表只记录boreal最低价为cedar并稳定排序。答案在lessons/06/answer_previous.py。它刻意继续使用串行for循环先把“部分失败”的业务行为和“并发执行”的调度行为分开验收。答案中的try只包住一次fetch捕获ProviderFailure后追加一条失败循环继续。成功报价统一交给summarize排序。若把整个循环包在一个try中boreal失败之后cedar就没有机会被询问即使最后仍能返回atlas也不满足“尽量保留结果”的合同。末尾附答案全部源码。从工作线程提交到主线程领取ThreadPoolExecutor(max_workers3)最多同时运行三个工作线程。submit(tracked, supplier)提交可调用对象及参数立即返回一个Future。Future是任务最终结果的位置不是结果本身它可能排队中、运行中、成功或失败。用字典保存future - supplier非常必要。请求失败时没有报价行可用于识别供应商但Future仍能映射回提交对象。这和“函数返回了谁”是两条独立的信息渠道。主线程从as_completed(futures)取得已经完成的Future再调用future.result()成功时得到行失败时在主线程重新抛出工作线程里的异常。as_completed按完成情况交付不承诺按提交顺序。正常延迟大约是cedar 0.09秒、atlas 0.12秒、boreal 0.18秒所以三线程演示经常先观察到cedar但操作系统调度、连接初始化和负载都能改变次序。程序打印completion_order帮助我们看这个事实业务代码不能依赖某次观察到的顺序。如果改成for future in futures: future.result()请求依然已经并发提交只是收集者可能卡在最早提交的慢任务上迟迟无法处理后面早已完成的结果。它不等于完全串行却失去了及时处理已完成工作的便利。这两个层次要分开任务何时运行由执行器决定结果何时被主线程消费由收集方式决定。为什么收集列表不加锁计数器却加锁本课工作线程只执行work和完成计数rows、failures、completion_order都由主线程修改因此这些容器没有多线程写入不需要给每个append包一把锁。减少共享状态通常比增加更多锁更容易推理。completed刻意保留为共享状态用来说明锁的边界。completed 1在语义上包含读取旧值、计算新值、写回不应把“某个CPython版本的一次压力测试没丢计数”当作原子性合同。GIL限制线程执行Python代码不代表任意复合业务操作都自动不可分割也不保证未来实现仍保持相同表现。with lock:只围住计数更新不围住HTTP调用。若持锁期间等待网络其他线程想更新计数就只能等待同一把锁若把整个请求也纳入同一个锁三个线程又退化为一次一个请求。临界区越长锁竞争越可能成为新的串行瓶颈。计数更新放在finally表示“已经结束的尝试数”包括成功、503、校验失败。它不是“成功报价数”。正常quantity2时三个请求都完成completed3但只有两个可售报价。指标名称必须对应实际语义否则监控会把正常缺货误报为丢任务。HTTPX同步Client可以在线程之间共享。本课只用它发送请求不在工作线程中同时修改默认headers、cookies或其他配置。客户端在外层with创建执行器退出并确认线程结束后才关闭它如果先关闭客户端再让线程继续发请求得到的会是生命周期错误而不是供应商错误。两个工作线程到底限制了什么运行命令均从课程根目录执行供应商保持在另一终端运行。Linux使用python3.11替换解释器名。python tools/provider_lab.py--port 9101python lessons/06/answer_previous.py python lessons/06/main.py--workers 3 python lessons/06/main.py--workers 2 python lessons/06/main.py--workers 2--scenario broken python lessons/06/timeout_demo.py python-m unittest discover-s lessons/06-p test_lesson.py-v设成2以后一开始最多两家运行第三家在执行器队列中等待空位。max_workers约束正在执行的线程数并不限制你总共调用多少次submit。这里总共只有三个任务排队规模天然有限如果把一百万个SKU都立即submit线程仍然只有两个但一百万个Future与参数仍要占内存。第10课会用有界队列控制生产速度。本课测试使用Barrier让两个工作者必须碰面后才能继续。如果错误地改成串行执行第一个工作者会等待不到第二个而失败独立计数器还检查峰值恰为2。测试随后使用相同总价验证供应商名称排序。这个断言抓的是实际资源行为和可见结果而不是只检查代码里是否写着max_workers2。最容易误用的超时等不及不等于杀掉线程timeout_demo.py用Event让线程停在一个可控位置。主线程调用future.result(timeout0.02)等待超时后打印running_after_timeoutTrue。紧接着调用future.cancel()已经开始运行的任务返回False。只有仍在排队、还没有开始的任务才可能被cancel取消。演示最后在finally里设置release事件工作线程正常返回避免留下一个永远阻塞的进程。这也说明线程池上下文管理器的退出语义默认会等待工作者收尾。即使主线程已经捕获Future超时离开with ThreadPoolExecutor(...)时仍可能继续等待。因此不能通过给result()设置0.8秒就宣称整个接口最多0.8秒。真实网络请求需要HTTP库自身的连接、读取等超时线程里的长CPU循环需要主动检查协作停止标记。如果底层第三方函数无法中止线程池不能替你安全杀死它。把shutdown(waitFalse)当成解决方案也不成立那只让当前调用不等待不会撤销已经运行的代码解释器退出通常仍会等待线程池任务。本课适合解释I/O重叠。对纯Python密集计算常见有GIL的CPython中多个线程通常不能让Python字节码同时在多个核心上跑下一课会为真正的CPU工作选择进程池。某些扩展库会释放GIL因此“所有CPU代码用线程都无效”也过于武断应该依据实际工作负载测量。E06把资源上限与业务顺序分开验收原题E06对三个正常供应商使用最多2个工作线程购买2件。可售结果必须按(total_cents, supplier)稳定排序正常结果依次是boreal 25900、atlas 26400cedar被库存规则过滤。再构造atlas与boreal总价相同的数据断言atlas在前不能依赖Future完成顺序。用测试中的活动计数证明峰值不超过2并让至少两个任务真实重叠。下一课提供完整答案。遇到错误先判断所属层若输出顺序偶尔变化检查是否忘了最后排序若峰值超过2检查是否还有额外执行器若超时后程序迟迟不退出检查运行中的线程是否有自己的退出条件。并发程序的问题不总是锁的问题找准被违反的合同更省力。一把锁保护的是不变量而不是某一行语法设想我们同时维护“完成数量”和“总耗时”。如果它们必须描述同一批已完成任务就应在同一个临界区内一起更新只分别给两个赋值加锁读取者可能看到新计数配旧耗时。设计锁之前先用一句话写清必须始终成立的关系再围住那段不可被别人看到中间状态的操作比逐行到处加锁更可靠。相反不需要共享的东西尽量留在工作者局部变量里。每个请求的开始时刻、响应对象和解析中间值属于这次调用不要为了“统一管理”放进全局字典让所有线程读写。主线程集中合并成功和失败也是同一个设计思路把跨线程协调缩到最少保留清楚的数据流。死锁往往来自不同代码以不同顺序获取多把锁。例如一条路径先拿计数锁再拿日志锁另一条先拿日志锁再等计数锁二者都可能握着对方需要的资源。当前例子只使用一把短时锁避免过早引入这种组合。真实系统无法避免多锁时应统一获取顺序并避免持锁调用未知的外部回调或阻塞操作。提交成功并不保证业务成功submit返回Future只表示执行器接受了任务不表示HTTP已经发出更不表示供应商成功。队列里的任务可能还没开始任务执行后也可能返回技术失败。因此服务不能在提交后立即把completed加一否则排队、运行和完成三个阶段会被混在一起。当前计数位于工作函数的finally明确指向执行结束。Future携带异常的行为也解释了为什么必须领取每个结果。如果只提交不调用result某些业务异常可能长时间无人观察表面上主线程没有报错实际却丢了一家报价。as_completed循环不仅为了收集快结果也是让每一个提交都有对应的结算位置。即使业务最终只选择最低价其他供应商任务也不能变成无人负责的后台工作。调线程数时先找瓶颈把工作线程从一改成二通常能重叠两段网络等待继续改成几十却未必有收益。这里只有三项工作多出来的额度没有可执行任务请求量更大时还会受客户端连接池、服务端容量、网络带宽以及本机调度限制。远端限流后增加线程可能把成功吞吐换成更多快速失败。公平比较应固定同一批输入、同样的失败策略和超时、同样的连接池生命周期并在预热后重复多轮。只比较一次终端命令的壁钟时间会把解释器启动、杀毒扫描和客户端初始化一起混进去。本课打印的是学习用观测值第十七课才使用一致边界测量分位数在那之前能够证明峰值受限和结果不变已经比一个偶然漂亮的倍数更有说服力。本课完整源码domain.py与gateway.py是05课规则和同步网关的原样副本独立保存是为了让本课目录不依赖未来项目。下面给出它们及所有新增实验的完整代码。lessons/06/answer_previous.pyE05: HTTP 503 must preserve successful providers.importosimporthttpxfromdomainimportSUPPLIERS,ProviderFailure,summarizefromgatewayimportfetchdefsolve():rows,failures[],[]base_urlos.getenv(QUOTEFLOW_PROVIDER_URL,http://127.0.0.1:9101)withhttpx.Client(trust_envFalse)asclient:forsupplierinSUPPLIERS:try:rows.append(fetch(client,base_url,supplier,broken,1))exceptProviderFailureasexc:failures.append({supplier:supplier,code:exc.code})resultsummarize(rows,failures,1)assert{row[supplier]forrowinresult[quotes]}{atlas,cedar}assertresult[best][supplier]cedarassertresult[failures][{supplier:boreal,code:http_503}]returnresultif__name____main__:print(solve())lessons/06/domain.pyShared business rules copied into each independent lesson.fromdataclassesimportasdict,dataclass SUPPLIERS(atlas,boreal,cedar)classProviderFailure(Exception):def__init__(self,code):self.codecodesuper().__init__(code)classInvalidData(ProviderFailure):def__init__(self):super().__init__(invalid_data)defvalidate_quantity(quantity):在任何外部调用前拒绝非法数量布尔值不能冒充整数。iftype(quantity)isnotintornot1quantity100:raiseValueError(quantity must be an integer from 1 to 100)dataclass(frozenTrue,slotsTrue)classQuote:supplier:strsku:strunit_cents:intshipping_cents:intstock:intclassmethoddefparse(cls,data,supplier,sku):在HTTP边界把不可信JSON变成身份、金额和库存均可信的报价。ifnotisinstance(data,dict):raiseInvalidData()ifdata.get(supplier)!supplierordata.get(sku)!sku:raiseInvalidData()forkeyin(unit_cents,shipping_cents,stock):iftype(data.get(key))isnotintordata[key]0:raiseInvalidData()returncls(supplier,sku,data[unit_cents],data[shipping_cents],data[stock])defrow(self,quantity):return{**asdict(self),total_cents:self.unit_cents*quantityself.shipping_cents}defsummarize(rows,failures,quantity):缺货是正常过滤最终排名由业务键决定与完成顺序无关。quotessorted((rowforrowinrowsifrow[stock]quantity),keylambdarow:(row[total_cents],row[supplier]))return{sku:KB-001,quantity:quantity,quotes:quotes,failures:sorted(failures,keylambdarow:row[supplier]),best:quotes[0]ifquoteselseNone}lessons/06/gateway.pyOne synchronous HTTP attempt; no retry and no batch time budget.fromtimeimportperf_counterimporthttpxfromdomainimportInvalidData,ProviderFailure,Quotedeffetch(client,base_url,supplier,scenario,quantity):只执行一次HTTP尝试客户端归调用者所有此处不创建、不关闭。startedperf_counter()try:responseclient.get(f{base_url}/quotes/{supplier},params{sku:KB-001,scenario:scenario},timeouthttpx.Timeout(0.6))receivedperf_counter()response.raise_for_status()excepthttpx.TimeoutExceptionasexc:raiseProviderFailure(timeout)fromexcexcepthttpx.HTTPStatusErrorasexc:raiseProviderFailure(fhttp_{exc.response.status_code})fromexcexcepthttpx.DecodingErrorasexc:# 坏gzip等内容编码错误是远端数据损坏不归类为可重试传输故障。raiseInvalidData()fromexcexcepthttpx.RequestErrorasexc:raiseProviderFailure(transport)fromexc# HTTP成功不保证数据合法解析错误在供应商边界转成明确类别。try:dataresponse.json()exceptValueErrorasexc:raiseInvalidData()fromexc quoteQuote.parse(data,supplier,KB-001)rowquote.row(quantity)row[http_ms]round((received-started)*1000,2)row[parse_ms]round((perf_counter()-received)*1000,2)returnrowlessons/06/main.pyBounded thread pool: completion order differs from ranking order.importargparsefromconcurrent.futuresimportThreadPoolExecutor,as_completedimportjsonimportosimportthreadingfromtimeimportperf_counterimporthttpxfromdomainimportSUPPLIERS,ProviderFailure,summarize,validate_quantityfromgatewayimportfetchdefrun_pool(work,quantity2,max_workers3):限制运行线程数结果只由主线程汇总避免无必要的共享写入。validate_quantity(quantity)rows,failures,completion_order[],[],[]completed0lockthreading.Lock()deftracked(supplier):# 计数代表结束的尝试包含失败锁只保护复合更新不包住HTTP等待。nonlocalcompletedtry:returnwork(supplier)finally:withlock:completed1withThreadPoolExecutor(max_workersmax_workers)aspool:futures{pool.submit(tracked,supplier):supplierforsupplierinSUPPLIERS}forfutureinas_completed(futures):supplierfutures[future]completion_order.append(supplier)try:rows.append(future.result())exceptProviderFailureasexc:failures.append({supplier:supplier,code:exc.code})resultsummarize(rows,failures,quantity)result.update(completedcompleted,completion_ordercompletion_order)returnresultdefmain():parserargparse.ArgumentParser()parser.add_argument(--scenario,defaultnormal)parser.add_argument(--workers,typeint,default3)argsparser.parse_args()base_urlos.getenv(QUOTEFLOW_PROVIDER_URL,http://127.0.0.1:9101)startedperf_counter()withhttpx.Client(trust_envFalse)asclient:resultrun_pool(lambdaname:fetch(client,base_url,name,args.scenario,2),max_workersargs.workers)result[elapsed_ms]round((perf_counter()-started)*1000,2)print(json.dumps(result,ensure_asciiFalse,indent2))if__name____main__:main()lessons/06/test_lesson.pyimportthreadingimporttimeimportunittestfrommainimportrun_poolclassLessonTests(unittest.TestCase):deftest_two_threads_overlap_but_never_exceed_capacity_and_sort(self):lockthreading.Lock()activepeak0readythreading.Barrier(2)defwork(name):nonlocalactive,peakwithlock:active1peakmax(peak,active)try:ifnamein(atlas,boreal):ready.wait(timeout2)time.sleep(0.02)returndict(suppliername,total_cents100,stock100)finally:withlock:active-1resultrun_pool(work,quantity2,max_workers2)self.assertEqual(peak,2)self.assertEqual(active,0)self.assertEqual([q[supplier]forqinresult[quotes]],[atlas,boreal,cedar])self.assertEqual(result[completed],3)if__name____main__:unittest.main()lessons/06/timeout_demo.pyA future timeout only stops waiting; it cannot kill a running thread.fromconcurrent.futuresimportThreadPoolExecutor,TimeoutErrorfromthreadingimportEventdefmain():entered,releaseEvent(),Event()defwork():entered.set()release.wait()returnfinished after releasewithThreadPoolExecutor(max_workers1)aspool:futurepool.submit(work)try:assertentered.wait(timeout2)try:future.result(timeout0.02)exceptTimeoutError:print({running_after_timeout:future.running(),cancel_succeeded:future.cancel()})else:raiseAssertionError(worker should still be waiting)assertfuture.running()finally:release.set()print(future.result(timeout2))if__name____main__:main()

相关新闻

ai-cli-claude 接入 TaoToken:把 settings 改到统一 Key 通道的配置大纲

ai-cli-claude 接入 TaoToken:把 settings 改到统一 Key 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 18:57:17 阅读更多 →
模糊RBF网络MATLAB实战:参数推导、可执行代码与4类翻车排查

模糊RBF网络MATLAB实战:参数推导、可执行代码与4类翻车排查

简介:本资源是面向高校自动化、智能控制与人工智能方向师生的MATLAB优化算法教学课件,聚焦模糊RBF神经网络的原理剖析、结构建模与工程实现。课件系统讲解RBF网络的局部逼近特性、三层前向结构、高斯基函数设计、权值/基宽/中心点联合优化方法&#xff0…

2026/10/17 18:57:17 阅读更多 →
Python校园志愿服务管理系统开题答辩:设计思路与高频问答复盘

Python校园志愿服务管理系统开题答辩:设计思路与高频问答复盘

这段经历还得从答辩教室的空调声说起。说实话,开题答辩之前,我一直以为它是个“走过场”——反正选题都定了、框架也搭出来了,老师象征性问两句也就结束了。真正站在讲台上讲完那十分钟,面对评委老师接二连三的追问时,…

2026/10/17 18:56:16 阅读更多 →

最新新闻

Mac Mouse Fix 入门指南:让 Mac 上的普通鼠标获得触控板级滚动与侧键操作

Mac Mouse Fix 入门指南:让 Mac 上的普通鼠标获得触控板级滚动与侧键操作

Mac Mouse Fix 入门指南:让 Mac 上的普通鼠标获得触控板级滚动与侧键操作 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 如果你用过…

2026/10/18 1:20:43 阅读更多 →
如何防止重要项目被误删?CleanMyMac CLI ignore白名单使用教程

如何防止重要项目被误删?CleanMyMac CLI ignore白名单使用教程

【免费下载链接】cleanmymac-cli Clean Xcode, Docker, Homebrew, and developer caches, remove project and AI artifacts, analyze storage, and reclaim disk space from the Terminal. 项目地址: https://gitcode.com/gh_mirrors/cl/cleanmymac-cli 点击查看 免…

2026/10/18 1:20:43 阅读更多 →
如何用 Codex-X 搭起逆向 Skills 分析链路:从 APK 到协议还原的完整实战

如何用 Codex-X 搭起逆向 Skills 分析链路:从 APK 到协议还原的完整实战

如何用 Codex-X 搭起逆向 Skills 分析链路:从 APK 到协议还原的完整实战 【免费下载链接】Codex-X OpenAI Codex 桌面端/CLI 的可视化管理工具,具有Provider/API 切换、会话同步、提示词注入、Skills/MCP 管理、TOML 配置可视化的跨平台工具。 项目地址…

2026/10/18 1:20:43 阅读更多 →
Wand-Enhancer 免费激活 WeMod Pro 功能:从构建到手机远程操控的完整实操教程

Wand-Enhancer 免费激活 WeMod Pro 功能:从构建到手机远程操控的完整实操教程

Wand-Enhancer 免费激活 WeMod Pro 功能:从构建到手机远程操控的完整实操教程 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer 想免费用…

2026/10/18 1:20:43 阅读更多 →
res-downloader 三步把视频号加密视频存到本地

res-downloader 三步把视频号加密视频存到本地

res-downloader 三步把视频号加密视频存到本地 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 下下来的 MP4 只有声音没画面&…

2026/10/18 1:20:43 阅读更多 →
Java计算两个日期之间的工作日天数:排除周末、节假日与调休的完整方案

Java计算两个日期之间的工作日天数:排除周末、节假日与调休的完整方案

简介:这是一份面向Java开发者的日期计算实战资料,聚焦「计算两个日期之间的天数并排除节假日与周末」这一常见业务需求,适合需要实现请假天数、工作日统计等功能的初中级开发者参考。资源以PDF形式呈现,压缩包内共1个文件&#xf…

2026/10/18 1:19:42 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →