Python进阶与并发编程12:把报价协程接到HTTP入口,资源该活多久
Python进阶与并发编程12把报价协程接到HTTP入口资源该活多久前几课的程序有一个明确的主人asyncio.run(main())启动事件循环main等待子任务最后关闭客户端。现在业务同事希望从网页提交“买两把键盘三家谁最便宜”。如果简单把main()粘到路由函数里每来一次请求就创建线程池、事件循环或 HTTP 客户端单次演示仍可能成功但服务的资源关系已经变了。Web 服务有很多次请求应用本身只启动一次我们需要先分清这两种寿命再把已经验证的业务规则接到入口。本课结束的代码在checkpoints/12/。它只有健康检查和单项报价接口没有第13课的全局准入与总预算没有第14课的重试更没有批次接口。这里保留每次 HTTP 操作的超时来避免无限等待但不能据此声称“整个请求只会运行0.8秒”。这个缺口会成为下一课的实际问题。先兑现E11取消不是发出一句命令就算结束E11要求六个慢任务共用Semaphore(2)取消批次后把它等到退出确认活动计数归零再复用同一个信号量完成下一批同时恢复 ContextVar。完整答案是lessons/12/answer_previous.py从课程根目录运行python lessons/12/answer_previous.py答案用two_entered事件确认恰有两个任务进入资源区再调用batch.cancel()。这样取消测试没有依赖“睡0.1秒应该已经开始”的猜测。cancel()只请求取消真正让 TaskGroup 取消其余孩子、等待孩子执行finally的是随后那次await batch。调用方捕获CancelledError是为了在验证取消之后继续测试下一批并不是业务协程吞掉取消。active - 1放在资源区内部的finally因此任务在睡眠时收到取消计数也会减少async with gate.slot()则负责归还槽位。ContextVar 使用token set(...)与reset(token)配对恢复的是进入前的值而非盲目改成某个字符串。父任务的上下文与创建时复制给子任务的上下文也不能混为一谈所以答案既在批次的 finally 内断言恢复又在调用方断言仍为预设的caller-before。下一批输入[3,4,5]在宽容1秒期限内返回[6,8,10]且每行ID为next峰值不超过2给出了“资源能再次使用”的行为证据比读取信号量私有字段更有价值。这个收尾关系将在 Web 中继续存在应用 lifespan 等待共享客户端关闭请求任务的 TaskGroup 等待供应商任务结束。所谓资源管理不是每层都加一个 try而是能回答每个资源由谁创建、谁借用、谁最后关闭。只检查下一批最终完成尚不能证明两个槽位都回来了如果意外漏还一个槽位小批次仍可能串行跑完。答案还清空旧事件让两个新的holder在同一gate中等待release确认两者同时进入、active再次达到2再放行。它不读取Semaphore私有字段也不复用取消前的历史peak当作恢复证据。请求合同先于路由代码我们把调用方可以决定的内容限定为 SKU、数量和教学故障场景。例如{sku:KB-001,quantity:2,scenario:normal}SKU 默认KB-001数量默认2允许1–100的整数场景只允许 normal、slow、broken、malformed、flaky。调用方不能提供供应商 URL因此不能借我们的服务任意访问本机或其他地址。教学场景开关用于稳定复现故障不应直接照搬成线上客户的业务参数。数量使用strictTrue因为 JSON 的true、字符串2与整数2含义不同。Python 中布尔值是整数的子类是本系列第一课谈过的类型边界这里不能只写一个宽松的大小比较便放心。extraforbid使拼错的字段和额外 URL 得到422避免“客户端以为参数生效服务却忽略了它”。SKU长度有上限空字符串无意义未知但格式正确的SKU则仍可向供应商查询由供应商404给出技术失败结果。FastAPI根据QuoteRequest解析请求校验不通过时不会执行报价路由。这个顺序很重要quantity0不只是返回错误还应完全不触碰供应商。下一课的E12答案会验证这一点。响应也声明response_modelQuoteResult让文档和代码共享结构约束。响应校验不是装饰如果我们不小心返回不符合约定的数据服务应暴露程序错误而不是把错误结构当正常合同发送给客户。同时信任两边输入会把错误变成低价外部调用方是一处边界供应商 HTTP 响应是另一处。供应商即使返回200也可能给出unit_centsunknown或在 atlas 路径返回 boreal 的数据。SupplierQuote校验金额和库存都是非负整数随后_fetch还比较响应中的 supplier、sku与本次请求是否一致。若只校验字段存在串错货号的合法 JSON 就可能参与排名。金额全程按“分”存储合计严格是unit_cents * quantity shipping_cents。运输费不是每件一份不能把(unit_cents shipping_cents) * quantity写成看似自然的公式。正常数量2时atlas总额26400分boreal25900分cedar库存只有1属于有效但不可售的报价所以过滤掉而不记供应商失败。failures记录传输、状态码、畸形数据等技术问题缺货不等于供应商坏了。成功结果按(total_cents, supplier)排序。虽然三个任务的完成顺序不稳定HTTP响应的展示顺序是稳定的最低价同价时也可复现。best是排序后的第一项若没有可售报价则为null。因此“全部供应商正常但都缺货”与“全部技术失败”都可能 bestnull客户仍可通过failures了解两者差别。响应还有JSON之前的解码边界若供应商声明Content-Encoding: gzip正文却无法解压HTTPX会在client.get()读取期间抛DecodingError。它继承RequestError而非TransportError现有传输错误分支无法顺便兜住。我们在HTTP读取边界单独把它转为invalid_data保留其他供应商结果稍后的JSON解析和字段校验则分别负责后续边界。一个应用借用一个客户端create_app构造 FastAPI 应用它接收的可选transport用于测试替换网络边界默认值不设置MockTransport实际启动就会走真实HTTP。应用模块最后的app create_app()只构造应用不在导入时打开网络连接。导入期创建长寿命异步资源容易把资源绑定到不合适的事件循环也让测试与多进程启动变得含糊。lifespan是异步上下文管理器。进入时创建httpx.AsyncClient把持有它的QuoteService放到app.stateyield之后是应用运行期退出时由async with等待客户端关闭。每次路由拿到的都是同一服务实例每次_fetch借用同一连接池。请求结束不关闭客户端因为别的请求还可能使用它应用结束才承担最终关闭责任。这里的共享不是靠模块变量碰巧指向同一个对象而是由应用生命周期明确拥有。trust_envFalse避免机器上的代理环境变量意外接管本地实验请求供应商地址由QUOTEFLOW_PROVIDER_URL配置默认回环地址9101端口关闭重定向跟随则防止在未审查的新地址继续取报价。它们让实验路径更可解释并不替代真实部署的网络访问控制。同一个路由中的三种错误处理位置不同输入非法由框架返回422单个供应商503被转换为Failure(supplierboreal, codehttp_503)其余报价保留整个查询仍可返回200代码自己抛出的RuntimeError等程序错误则不伪装成供应商失败。第三种应保留异常与服务器日志让我们修正缺陷。把整个路由包进except Exception: return []会同时隐藏拼错变量、错误字段和网络失败调用方只会看见一个莫名其妙的空榜单。TaskGroup适合表达三个子任务都属于当前查询。每个子任务先在自己的HTTP边界把预期故障转成值这样boreal503不会取消atlas真正未预期的异常仍由TaskGroup汇总并取消兄弟任务。我们使用task.result()只发生在TaskGroup正常退出之后届时每个任务都已结束不会凭空读取一个尚未完成的结果。不要在async def路由中调用asyncio.run()。ASGI服务器已经管理事件循环服务方法直接await异步客户端让出等待网络的时间。也不要误以为“路由是async所以里面的任何函数都不会阻塞”若在里面调用time.sleep()或同步HTTP事件循环仍会被阻塞。前几课学习的调度规则没有因为加上路由装饰器而改变。从独立阶段安装再观察真实数据先在课程根目录的一个终端启动供应商python tools/provider_lab.py --port 9101。另一个终端进入checkpoints/12使用Python3.11建立独立环境避免默认python恰好指向3.9py-3.11-m venv.venv.\.venv\Scripts\python.exe-m pip install-e.[test].\.venv\Scripts\python.exe-m pytest-q.\.venv\Scripts\python.exe-m uvicorn quoteflow.api:app--host 127.0.0.1--port 9100Linux使用python3.11 -m venv .venv后续解释器为.venv/bin/python。不同阶段包名都叫quoteflow必须各用自己的环境不能在同一个环境同时editable安装四个阶段。Invoke-RestMethod-Method Post-Uri http://127.0.0.1:9100/api/quotes-ContentType application/json-Body{sku:KB-001,quantity:2,scenario:normal}把场景换成broken应看到boreal技术失败但atlas仍可售换成malformed应看到invalid_data。此阶段还没有重试所以flaky首试会失败。GET /health返回{status:ok}表示进程能够处理这个简单入口不表示所有供应商可用。阶段测试使用MockTransport控制供应商结果使用ASGITransport直接执行应用。这样可以精确验证HTTP模型、业务结果及lifespan是否关闭客户端但没有经过TCP、端口绑定或真实连接池。本课真实演示与进程内测试必须分别描述后面会有独立的双进程黑盒验收。一个正常响应能说明哪些事不能说明哪些事如果页面展示了boreal最低价只能说明本次查询中可售且已成功返回的报价经过了正确计算与比较。它不自动证明报价一定最新也不证明所有市场供应商都已被覆盖。我们把报价时间、币种、有效期等真实业务字段暂时排除在教学合同之外避免初学者同时承受太多维度读者必须能指出这个简化不能把教学字段直接当采购合同使用。另外进程内测试里健康供应商常常马上返回容易让人误以为异步任务总按创建顺序完成。真实服务器故意让cedar比atlas快、atlas比boreal快让调度与排序的区别可见。输出quotes的第一个元素是总价最小而不是最先收到响应。响应中的elapsed_ms是整次聚合经历的时间也不能拿三家延迟相加后解释为它的必然值。当你关闭服务进程时服务器会先处理自己的退出流程然后离开lifespan客户端的async with负责释放池中连接。若使用强制终止进程操作系统仍会回收进程资源但Python finally不一定执行。课程选择正常退出的生命周期测试是为了验证应用能控制的清理路径而非声称代码能抵御任意强杀。阅读代码时可以手动走一次broken输入Pydantic确认quantity是2路由借用服务三个任务共享客户端boreal变成Failurecedar因库存不足被过滤atlas带26400分总价进入quotes与best。这条逐值路径比背“FastAPI高性能、异步高并发”更能说明程序到底做了什么。最后检查一次响应字段的单位total_cents、unit_cents、shipping_cents都是分elapsed_ms是毫秒quantity是件数。字段名字承担了避免误读的责任前端展示元时再做格式化。不要把金额为浮点元和整数分混在同一个字段里也不要把秒数直接写入带ms后缀的字段。接口一旦被其他客户端使用这些小单位约定就成了需要长期维护的合同。E12让无效数量在网络之前停止提交quantity0断言HTTP状态码为422供应商测试transport计数必须保持0。测试需要显式进入应用lifespan否则没有模拟完整启动生命周期。再试quantitytrue与quantity“2”理解严格整数为何值得保留。验收重点不是把报错截图贴上来而是证明无效输入没有消耗出站资源。答案将在第13课给出完整可运行文件位于lessons/13/answer_previous.py。第12课的核心文件全文如下均来自本课独立阶段不包含后续重试、全局预算或批次代码。本课完整代码lessons/12/answer_previous.pyE11 完整自包含答案复用共享 gate恢复调用前 ContextVar。importasynciofromcontextlibimportasynccontextmanagerfromcontextvarsimportContextVar request_idContextVar(request_id,default-)classResourceGate:def__init__(self,limit):iflimit1:raiseValueError(limit must be positive)self.semaphoreasyncio.Semaphore(limit)self.active0self.peak0self.two_enteredasyncio.Event()asynccontextmanagerasyncdefslot(self):asyncwithself.semaphore:self.active1self.peakmax(self.peak,self.active)ifself.active2:self.two_entered.set()try:yieldfinally:self.active-1asyncdefrun_batch(items,gate,batch_id,delay0.03):previousrequest_id.get()tokenrequest_id.set(batch_id)results[None]*len(items)try:asyncdefone(index,item):asyncwithgate.slot():awaitasyncio.sleep(delay)results[index]{value:item*2,request_id:request_id.get()}asyncwithasyncio.TaskGroup()asgroup:forindex,iteminenumerate(items):group.create_task(one(index,item))returnresultsfinally:request_id.reset(token)assertrequest_id.get()previousasyncdefmain():tokenrequest_id.set(caller-before)try:gateResourceGate(2)batchasyncio.create_task(run_batch(list(range(6)),gate,cancel-me,delay5))awaitgate.two_entered.wait()assertgate.active2batch.cancel()try:awaitbatchexceptasyncio.CancelledError:pass# 调用方确认收到了取消run_batch 本身没有吞取消。else:raiseAssertionError(外部取消必须传播到调用方)assertgate.active0# 旧peak可能来自取消前让两位新holder同时进入证明两槽都归还。gate.two_entered.clear()releaseasyncio.Event()asyncdefhold_slot():asyncwithgate.slot():awaitrelease.wait()asyncwithasyncio.TaskGroup()asgroup:group.create_task(hold_slot())group.create_task(hold_slot())awaitasyncio.wait_for(gate.two_entered.wait(),timeout1)assertgate.active2release.set()assertgate.active0asyncwithasyncio.timeout(1):rowsawaitrun_batch([3,4,5],gate,next)assert[row[value]forrowinrows][6,8,10]assert{row[request_id]forrowinrows}{next}assertgate.active0andgate.peak2assertrequest_id.get()caller-beforefinally:request_id.reset(token)print(E11 passed: active0, peak2, results[6,8,10], context restored)if__name____main__:asyncio.run(main())checkpoints/12/pyproject.toml[build-system] requires [setuptools68,81] build-backend setuptools.build_meta [project] name quoteflow-course version 1.0.0 description Python 3.11 bounded concurrency teaching service requires-python 3.11 dependencies [fastapi0.115.12, httpx0.28.1, uvicorn0.34.2, pydantic2.7,3] [project.optional-dependencies] test [pytest8.3.5] [tool.pytest.ini_options] testpaths [tests] pythonpath [src]checkpoints/12/src/quoteflow/__init__.pyStandalone course checkpoint.checkpoints/12/src/quoteflow/models.pyfromtypingimportAnnotated,LiteralfrompydanticimportBaseModel,ConfigDict,Field SupplierLiteral[atlas,boreal,cedar]ScenarioLiteral[normal,slow,broken,malformed,flaky]NonnegativeIntAnnotated[int,Field(strictTrue,ge0)]classQuoteRequest(BaseModel):入口严格校验布尔值、字符串数量和调用方自定义 URL 均被拒绝。model_configConfigDict(extraforbid)sku:strField(defaultKB-001,min_length1,max_length64)quantity:intField(default2,strictTrue,ge1,le100)scenario:ScenarionormalclassSupplierQuote(BaseModel):供应商是另一处不可信边界金额分与库存必须为非负整数。model_configConfigDict(extraforbid,frozenTrue)supplier:Supplier sku:strunit_cents:NonnegativeInt shipping_cents:NonnegativeInt stock:NonnegativeIntclassRankedQuote(SupplierQuote):total_cents:NonnegativeIntclassFailure(BaseModel):supplier:Supplier code:strclassQuoteResult(BaseModel):sku:strquantity:intquotes:list[RankedQuote]failures:list[Failure]best:RankedQuote|Noneelapsed_ms:floatrequest_id:strcheckpoints/12/src/quoteflow/service.pyFirst web stage: shared client, no global admission or total deadline yet.importasynciofromtimeimportperf_counterfromuuidimportuuid4importhttpxfrompydanticimportValidationErrorfrom.modelsimportFailure,QuoteRequest,QuoteResult,RankedQuote,SupplierQuote SUPPLIERS(atlas,boreal,cedar)classQuoteService:def__init__(self,client:httpx.AsyncClient):self.clientclientasyncdef_fetch(self,supplier,query,request_id):try:responseawaitself.client.get(f/quotes/{supplier},params{sku:query.sku,scenario:query.scenario},headers{X-Request-ID:request_id},)excepthttpx.DecodingError:# gzip 等响应体解码在 client.get 内发生属于供应商数据错误。returnFailure(suppliersupplier,codeinvalid_data)excepthttpx.TimeoutException:returnFailure(suppliersupplier,codetimeout)excepthttpx.TransportError:returnFailure(suppliersupplier,codetransport_error)ifresponse.status_code!200:returnFailure(suppliersupplier,codefhttp_{response.status_code})try:quoteSupplierQuote.model_validate(response.json())except(ValueError,ValidationError):returnFailure(suppliersupplier,codeinvalid_data)ifquote.supplier!supplierorquote.sku!query.sku:returnFailure(suppliersupplier,codeinvalid_data)returnquoteasyncdefquote(self,query:QuoteRequest)-QuoteResult:started,request_idperf_counter(),uuid4().hexasyncwithasyncio.TaskGroup()asgroup:tasks[group.create_task(self._fetch(name,query,request_id))fornameinSUPPLIERS]quotes,failures[],[]fortaskintasks:valuetask.result()ifisinstance(value,Failure):failures.append(value)elifvalue.stockquery.quantity:quotes.append(RankedQuote(**value.model_dump(),total_cents(value.unit_cents*query.quantityvalue.shipping_cents)))quotes.sort(keylambdaquote:(quote.total_cents,quote.supplier))returnQuoteResult(skuquery.sku,quantityquery.quantity,quotesquotes,failuresfailures,bestquotes[0]ifquoteselseNone,elapsed_msround((perf_counter()-started)*1000,3),request_idrequest_id)checkpoints/12/src/quoteflow/api.pyimportosfromcontextlibimportasynccontextmanagerimporthttpxfromfastapiimportFastAPI,Requestfrom.modelsimportQuoteRequest,QuoteResultfrom.serviceimportQuoteServicedefcreate_app(*,transportNone)-FastAPI:asynccontextmanagerasyncdeflifespan(app):# 启动时创建一次应用关闭时等待 aclose每次请求只借用客户端。asyncwithhttpx.AsyncClient(base_urlos.getenv(QUOTEFLOW_PROVIDER_URL,http://127.0.0.1:9101),timeouthttpx.Timeout(0.8),transporttransport,trust_envFalse,follow_redirectsFalse,)asclient:app.state.serviceQuoteService(client)yieldappFastAPI(titleQuoteFlow,version1.0.0,lifespanlifespan)app.get(/health)asyncdefhealth():return{status:ok}app.post(/api/quotes,response_modelQuoteResult)asyncdefquotes(query:QuoteRequest,request:Request):returnawaitrequest.app.state.service.quote(query)returnapp appcreate_app()

相关新闻

西门子PLC生产测速与产量统计程序的设计实践

西门子PLC生产测速与产量统计程序的设计实践

车间主任问一句“这一班下来干出多少件”,很多人第一反应是——PLC里加个计数器不就行了。但等你真的用西门子PLC去做一套生产测速产量统计程序,你会发现难点从来不是“计数”,而是“口径”:当班生产量、生产总量、生产时间参数&a…

2026/10/19 3:56:26 阅读更多 →
GeoServer 挂载 ArcGIS 切片:免授权发布 WMTS/TMS 瓦片服务实战

GeoServer 挂载 ArcGIS 切片:免授权发布 WMTS/TMS 瓦片服务实战

简介:本资源面向需要在 GeoServer 中发布 ArcGIS 瓦片服务的 GIS 开发者与运维人员,尤其适合已有基础、希望打通切片发布与地图服务链路的中高级用户。压缩包共 1571 个文件,约 137.36MB,以 png 瓦片图片、jar 依赖库、xml 配置、…

2026/10/19 3:56:26 阅读更多 →
open-code-review:开源协作驱动的智能代码审查范式

open-code-review:开源协作驱动的智能代码审查范式

1. 什么是 open-code-review:它不是另一个代码审查工具,而是一套可落地的开源协作范式“open-code-review”这个词最近在 GitHub Trending 和技术社区讨论中频繁出现,但它既不是某个具体 SaaS 服务的商标名,也不是某家公司的私有产…

2026/10/19 3:56:26 阅读更多 →

最新新闻

ARM板子上跑通海康威视SDK:交叉编译与C++工程避坑全记录

ARM板子上跑通海康威视SDK:交叉编译与C++工程避坑全记录

简介:交叉编译是嵌入式Linux开发中的基础环节,其核心在于工具链、系统架构与目标运行环境的匹配。它解决了资源受限设备无法本地编译的问题,让开发者可以在高性能宿主机上为ARM板卡生成可执行程序。在物联网与边缘计算场景下,x86端…

2026/10/19 4:36:50 阅读更多 →
基于Git钩子与本地LLM的开源代码审查工作流

基于Git钩子与本地LLM的开源代码审查工作流

1. 项目概述:这不是一个“工具”,而是一套可落地的代码审查新工作流open-code-review 这个名字乍看像某个开源项目仓库,但实际它代表的是一种正在快速成型的工程实践范式——把大语言模型(LLM)深度嵌入到日常 Git 工作…

2026/10/19 4:36:50 阅读更多 →
开源Git Diff驱动的AI代码评审系统:CLI优先、上下文感知、可嵌入开发流

开源Git Diff驱动的AI代码评审系统:CLI优先、上下文感知、可嵌入开发流

1. 项目概述:这不是又一个“AI写代码”玩具,而是一套可嵌入日常开发流的开源代码评审系统“open-code-review”这个名字乍看平平无奇,但拆开来看——open不是指“开源”,而是指“开放介入、开放集成、开放上下文”;cod…

2026/10/19 4:36:50 阅读更多 →
开源代码审查CLI工具:Git原生集成+本地LLM驱动

开源代码审查CLI工具:Git原生集成+本地LLM驱动

1. 项目概述:一个真正能落地的开源代码审查 CLI 工具“open-code-review”这个名字乍一听像某个 GitHub 上刚建的空仓库,但如果你最近在团队里被 PR 堆得喘不过气,或者自己写完一段 Python 脚本总担心漏掉边界条件、硬编码、安全漏洞&#xf…

2026/10/19 4:36:50 阅读更多 →
Tomcat 7 + JSP + JDBC 个人日记本实战教程

Tomcat 7 + JSP + JDBC 个人日记本实战教程

简介:这是一份面向Java Web初学者与课程设计者的JSP个人日记本实战源码,基于JSPMySQL技术栈构建完整的B/S架构日记管理应用,覆盖用户登录、日记增删改查、分类管理、个人中心等核心功能,适用于Web开发入门实践、毕业设计参考及Ser…

2026/10/19 4:36:50 阅读更多 →
从橡皮鸭调试法到拆解AI黑盒:可解释性实践指南

从橡皮鸭调试法到拆解AI黑盒:可解释性实践指南

1. 那只橡皮鸭到底是怎么回事1.1 橡皮鸭调试法的由来与基本操作先说个我自己的经历。有段时间我调一个数据处理脚本,逻辑怎么查都查不出毛病,数据一跑就错,但错得又很有规律。我盯着屏幕半小时,愣是没看出问题。后来同事路过&…

2026/10/19 4:35:48 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 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/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于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/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 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/19 2:54:50 阅读更多 →
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/18 12:16:16 阅读更多 →