新闻详情

新闻详情

首页 / 资讯中心 / 详情

【HarmonyOS开发小实践】Worker 创建、生命周期与多级 Worker

发布时间:2026/9/30 8:46:15来源:尧图网络
【HarmonyOS开发小实践】Worker 创建、生命周期与多级 Worker
Worker 创建、生命周期与多级 WorkerTaskPool 用起来简单但碰到要长时间占据线程、需要保存句柄状态、或者任务超过 3 分钟的场景就得请出 Worker 了。Worker 给你一个独立的运行环境自己管生命周期自己跟主线程消息通信自由度更高代价就是写起来更繁琐。这篇文章把 Worker 的运作机制、创建方式、文件路径规则、生命周期管理和多级 Worker 用法都过一遍。Worker 的运作机制Worker 子线程拥有独立的 ArkTS Runtime 实例包括独立的内存空间、消息队列MessageQueue、事件轮询机制EventLoop、调用栈CallStack。和主线程一样是个完整的执行环境只是没有 UI 能力。Worker 线程主线程postMessage序列化postMessage序列化onMessageonMessageArkTS Main Thread独立 RuntimeMessageQueueArkTS Worker Thread独立 RuntimeMessageQueue主线程和 Worker 线程通过postMessage互相发消息数据通过序列化传输。每个 Worker 启动都有内存开销独立的 Runtime 实例所以系统限制了 Worker 数量上限。多核 CPU 上多个 Worker 线程可以真正并行执行这是真并发不是时间片轮转。创建 WorkerWorker 线程文件必须放在{moduleName}/src/main/ets/目录层级之下否则不会被打包到应用里。创建方式有两种自动创建推荐。在 DevEco Studio 里右键{moduleName}目录下任意位置 New Worker自动生成模板文件和 build-profile.json5 配置省事。手动创建。自己建文件然后在 build-profile.json5 里配置// Stage 模型buildOption:{sourceOption:{workers:[./src/main/ets/workers/worker.ets]}}// FA 模型buildOption:{sourceOption:{workers:[./src/main/ets/MainAbility/workers/worker.ets]}}漏配的话 Worker 文件不会被打包运行时找不到文件会报错。文件路径规则构造 Worker 实例时要传入 Worker 线程文件路径scriptURL。Stage 模型下有三种写法写法一{moduleName}/ets/{relativePath}import{worker}fromkit.ArkTS;// 文件在 entry/src/main/ets/workers/worker.etsconstworker1:worker.ThreadWorkernewworker.ThreadWorker(entry/ets/workers/worker.ets);// 文件在 testworkers/src/main/ets/ThreadFile/workers/worker.etsconstworker2:worker.ThreadWorkernewworker.ThreadWorker(testworkers/ets/ThreadFile/workers/worker.ets);写法二{moduleName}/ets/{relativePath}import{worker}fromkit.ArkTS;// 加载 har 包里的 Worker文件在 har/src/main/ets/workers/worker.etsconstworker3:worker.ThreadWorkernewworker.ThreadWorker(har/ets/workers/worker.ets);写法三相对路径仅包内不支持跨包import{worker}fromkit.ArkTS;// 当前文件在 har/src/main/ets/components/mainpage/MainPage.ets// Worker 文件在 har/src/main/ets/workers/worker.etsconstworker4:worker.ThreadWorkernewworker.ThreadWorker(../../workers/worker.ets);跨包加载规则比较复杂整理成一张表加载方\被加载方entryfeature应用内 hsp跨工程 hsp源码 har三方 harentry写法一、三写法一写法一不支持写法二不支持feature不支持跨包写法一包内写法一、三写法一不支持写法二不支持应用内 hsp不支持写法一跨包写法一包内写法一、三不支持写法二不支持跨工程 hsp不支持不支持不支持不支持不支持不支持源码 har不支持写法一写法一不支持跨包写法二包内写法二、三不支持三方 har不支持不支持不支持不支持不支持仅包内写法三几个注意点加载 entry、feature、hsp 包的 Worker 不建议用写法三推荐写法一不用拼路径。文件路径后缀.ets/.ts可以省略。跨 HSP/HAR 包要在 oh-package.json5 里配依赖项。开启useNormalizedOHMUrl或 HAR 包被打包成三方包时HAR 包里 Worker 只能用相对路径创建。FA 模型下 scriptURL 是 Worker 文件相对于{moduleName}/src/main/ets/MainAbility的路径import{worker}fromkit.ArkTS;// 文件在 {moduleName}/src/main/ets/MainAbility/workers/worker.etsconstworkerFA1newworker.ThreadWorker(workers/worker.ets);// 文件在 {moduleName}/src/main/ets/workers/worker.etsconstworkerFA2newworker.ThreadWorker(../workers/worker.ets);生命周期管理Worker 创建后需要手动管生命周期。创建和销毁开销不小建议复用而不是频繁创建。空闲 Worker 仍然占资源不用了主动调terminate()或close()销毁。new ThreadWorker()postMessage 触发消息收发terminate() / close()onexit 回调完成CreatedRunningTerminatingTerminated几个关键点terminate()/close()是异步退出。注册的onexit()回调执行完线程才真正退出。Worker 已销毁或正在销毁时调功能接口会抛错。数量上限内存允许时最多 64 个 Worker加上 napi_create_ark_runtime 创建的 runtime 总数不超过 80。超限报错Worker initialization failure, the number of workers exceeds the maximum.内存阈值1.5GB 和设备物理内存 60% 中较小值。所有 Worker 主线程累积内存超阈值会触发 OOM 崩溃。基本用法示例主线程import{ErrorEvent,MessageEvents,worker}fromkit.ArkTS;EntryComponentstruct Index{build(){Column(){Button(start).onClick((){constworkerInstancenewworker.ThreadWorker(entry/ets/workers/worker.ets);// 接收 Worker 发来的消息在主线程执行workerInstance.onmessage(e:MessageEvents){console.info(onmessage:${e.data});};// 捕获 Worker 内全局异常在主线程执行workerInstance.onAllErrors(err:ErrorEvent){console.error(onAllErrors:${err.message});};// 接收到无法序列化的消息时调用workerInstance.onmessageerror(){console.error(onmessageerror);};// Worker 销毁时调用code0 正常退出code1 异常退出workerInstance.onexit(code:number){console.info(onexit code:${code});};// 发消息给 WorkerworkerInstance.postMessage(1);})}}}Worker 文件 worker.etsimport{ErrorEvent,MessageEvents,ThreadWorkerGlobalScope,worker}fromkit.ArkTS;constworkerPort:ThreadWorkerGlobalScopeworker.workerPort;// 收到主线程消息在 Worker 线程执行workerPort.onmessage(e:MessageEvents){console.info(workerPort onmessage: ,e.data);// 给主线程回消息workerPort.postMessage(2);};workerPort.onmessageerror(){console.error(workerPort onmessageerror);};workerPort.onerror(err:ErrorEvent){console.error(workerPort onerror: ,err.message);};主线程和 Worker 线程的回调是对称的主线程有onmessage/onAllErrors/onmessageerror/onexitWorker 线程有onmessage/onmessageerror/onerror。onAllErrors只在主线程侧有能捕获 Worker 线程里 onmessage、timer 回调以及文件执行等流程的全局异常。多级 WorkerWorker 可以创建子 Worker形成层级关系。父 Worker 在自己的 onmessage 里new worker.ThreadWorker(...)就能创建子 Worker。但生命周期管理要特别小心销毁父 Worker 前必须先销毁所有子 Worker否则会有不可预期的结果。推荐写法宿主线程import{worker,MessageEvents,ErrorEvent}fromkit.ArkTS;constparentWorkernewworker.ThreadWorker(entry/ets/workers/ParentWorker.ets);parentWorker.onmessage(e:MessageEvents){console.info(宿主线程收到父Worker消息 e.data);};parentWorker.onexit(){console.info(父Worker退出);};parentWorker.onAllErrors(err:ErrorEvent){console.error(父Worker报错 err.message);};parentWorker.postMessage(宿主线程发送消息给父Worker);ParentWorker.etsimport{ErrorEvent,MessageEvents,ThreadWorkerGlobalScope,worker}fromkit.ArkTS;constworkerPort:ThreadWorkerGlobalScopeworker.workerPort;workerPort.onmessage(e:MessageEvents){if(e.data宿主线程发送消息给父Worker){constchildWorkernewworker.ThreadWorker(entry/ets/workers/ChildWorker.ets);childWorker.onmessage(e:MessageEvents){console.info(父Worker收到子Worker消息 e.data);if(e.data子Worker向父Worker发送信息){workerPort.postMessage(父Worker向宿主线程发送信息);}};// 关键子 Worker 退出后再销毁父 WorkerchildWorker.onexit(){console.info(子Worker退出);workerPort.close();};childWorker.onAllErrors(err:ErrorEvent){console.error(子Worker报错 err.message);};childWorker.postMessage(父Worker向子Worker发送信息);}};ChildWorker.etsimport{MessageEvents,ThreadWorkerGlobalScope,worker}fromkit.ArkTS;constworkerPort:ThreadWorkerGlobalScopeworker.workerPort;workerPort.onmessage(e:MessageEvents){if(e.data父Worker向子Worker发送信息){console.info(业务执行结束);workerPort.postMessage(子Worker向父Worker发送信息);// 子 Worker 任务完成后主动退出workerPort.close();}};销毁顺序子 Workerclose()→ 触发子 Workeronexit→ 在子 Workeronexit里调父 Workerclose()→ 触发父 Workeronexit。这样保证父 Worker 销毁时子 Worker 已经不在了。反例 1父 Worker 销毁后子 Worker 还在发消息// ParentWorker.ets —— 错误示范workerPort.onmessage(e:MessageEvents){constchildWorkernewworker.ThreadWorker(entry/ets/workers/ChildWorker.ets);childWorker.onmessage(e:MessageEvents){console.info(父Worker收到子Worker消息 e.data);};childWorker.onexit(){// 父 Worker 已经或即将退出再通过父 Worker 端口发消息会出问题workerPort.postMessage(父Worker向宿主线程发送信息);};childWorker.postMessage(父Worker向子Worker发送信息);// 创建子 Worker 后立刻销毁父 Worker子 Worker 还在跑workerPort.close();};// ChildWorker.ets —— 错误示范workerPort.onmessage(e:MessageEvents){// 父 Worker 销毁后还往父 Worker 发消息workerPort.postMessage(子Worker向父Worker发送信息);setTimeout((){workerPort.postMessage(再发一次);// 父 Worker 已经没了},1000);};父 Worker 已经销毁子 Worker 发的消息没人接行为不可预期。反例 2父 Worker 发起销毁后再创建子 Worker// ParentWorker.ets —— 错误示范workerPort.onmessage(e:MessageEvents){workerPort.close();// 先发起销毁// 父 Worker 正在退出又创建子 WorkerconstchildWorkernewworker.ThreadWorker(entry/ets/workers/ChildWorker.ets);childWorker.postMessage(...);// 父 Worker 可能已经没了};创建子 Worker 前要确保父 Worker 处于存活状态。先close()再new ThreadWorker()顺序就反了。实践中要注意的手动管理生命周期。Worker 没有 TaskPool 那种自动扩缩容。创建销毁开销大复用为主。不用了一定要terminate()或close()不然空闲 Worker 一直占内存。数量上限 64 个。加上 napi runtime 总数不超过 80。超了直接报错。任务量大的场景用 TaskPool 更合适。内存阈值 1.5GB。实际可用数量根据内存动态调整。所有 Worker 主线程累积内存超阈值会 OOM 崩溃。监控内存占用及时销毁不用的 Worker。只能用线程安全的库。Worker 线程不能操作 UI不能用线程不安全的模块。AppStorage 也不支持在 Worker 里用。16MB 序列化限制。单次postMessage数据量上限 16MB。大数据用 ArrayBuffer 转移或 Sendable。Worker 文件里禁止 export。在 Worker 文件里export任何内容会导致 jscrash。Worker 文件就是个执行体不是模块。应用切后台 Worker 暂停。应用挂起切到后台后Worker 线程会暂停运行。回来后恢复。如果任务有时效要求注意这个行为。terminate 是异步的。调完terminate()后线程不是立刻退出要等onexit回调执行完。在这期间调 Worker 接口会抛错。需要等销毁完成再做后续操作的话把逻辑放在onexit里。多级 Worker 销毁顺序。销毁父 Worker 前先销毁所有子 Worker。推荐在子 Worker 的onexit里调父 Worker 的close()保证顺序正确。和 TaskPool 的根本差异是虾米Worker 给你一个完整的独立 Runtime自己管生命周期适合长时任务、需要保存状态、依赖线程上下文的场景。TaskPool 是线程池 调度器自动管理适合独立短任务。Worker 自由度高代价是代码量和心智负担TaskPool 简单但有 3 分钟和 16MB 的硬限制。选型其实不复杂任务超过 3 分钟、需要保存句柄状态、内存敏感用 Worker其他场景优先 TaskPool。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

GitHub打不开?今日热榜项目与访问异常自查指南 2026/9/30 13:47:49

GitHub打不开?今日热榜项目与访问异常自查指南

说实话,今天打开 GitHub 首页刷日榜的时候,我还挺意外的。倒不是说榜上项目有多炸裂,而是我看了看手边的热搜词,“github打不开”“github镜像”“github使用教程”这类的检索量明显又开始往上蹿了。我的后台私信里,每…

阅读更多 →
Redis原生AI能力实战:向量检索、MCP协议与agent-skills编排 2026/9/30 13:47:14

Redis原生AI能力实战:向量检索、MCP协议与agent-skills编排

1. 项目概述:Redis 已正式接入 AI —— 这不是营销话术,而是架构级融合的实操落地“Redis 已正式接入 AI!”——看到这个标题,你第一反应可能是:又一个蹭热点的标题党?AI 和 Redis 一个跑在 GPU 上&#xf…

阅读更多 →
Redis如何成为AI Agent的实时记忆中枢 2026/9/30 13:47:14

Redis如何成为AI Agent的实时记忆中枢

1. 项目概述:这不是“Redis AI”的营销噱头,而是协议层的真实融合 “Redis 已正式接入 AI!”——看到这个标题,我第一反应不是点开链接,而是抓起键盘连上本地 Redis 实例敲了条 INFO 命令。为什么?因为过…

阅读更多 →
5G QoS机制深度解析:从QoS Flow到端到端优化实践 2026/9/30 13:47:06

5G QoS机制深度解析:从QoS Flow到端到端优化实践

简介:《5G网络优化QoS管理机制》PPT课件面向5G网络优化工程师、无线接入网运维人员及通信专业学习者,系统讲解从4G EPS承载到5G QoS Flow的架构演进,并对QFI、5QI、GBR/Non-GBR、GFBR/MFBR等关键参数的定义与用途逐一说明。内容涵盖UPF、RAN、…

阅读更多 →
第73天算法刷题复盘:二分查找、贪心、堆与排序模块化实战 2026/9/30 13:47:05

第73天算法刷题复盘:二分查找、贪心、堆与排序模块化实战

1. 第73天,我决定把刷题节奏重新按“模块”切一遍刷到第73天这个节点,说实话心态和前几天完全不一样。前30天是硬扛,靠新鲜感撑着,一天三题不写出来不睡觉;40到60天开始进入一种机械状态,题目刷得挺多&…

阅读更多 →
计算机网络综合题高效复习:从题型拆解到协议栈贯通 2026/9/30 13:46:57

计算机网络综合题高效复习:从题型拆解到协议栈贯通

简介:围绕计算机网络课程中 IP 地址、子网划分、CIDR 路由与 VLAN 配置等高频综合题,整理出一份 doc 文档,汇编了多道典型计算与实例分析题,每题均附逐步解答和关键结论。内容覆盖二进制与十进制 IP 互换、地址类别判定、子网掩码…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉