鸿蒙主线程为什么不能卡

鸿蒙 UI 渲染跑在主线程(也叫 JS 线程)上。主线程一旦被一段耗时计算堵住,界面就掉帧、卡顿,甚至 ANR 报错。所以"别在主线程干重活"是鸿蒙开发的第一原则。

重活挪出去,主线程只负责画界面。

这篇讲鸿蒙三套并发工具:TaskPool、Worker、协程,以及什么时候用哪个。

主线程(UI 线程)每秒要跑满六十帧,留给一帧的时间也就十几毫秒。任何一次网络等待、一段大循环、一次图片解码,只要超过这个数,这一帧就掉了,用户看到的就是滑动卡顿。所以凡是"能算完再回来"的活,都别占着主线程。养成"看见耗时函数先想它该跑在哪"的习惯,应用的流畅度会上一个台阶。

TaskPool:任务池

TaskPool 是鸿蒙推荐的轻量并发方案:把一个函数丢进任务池,它会在后台线程跑完再把结果交回来。适合一次性的重计算,比如数据解析、图片处理。

import taskpool from '@ohos.taskpool';

@Concurrent
function heavyCompute(n: number): number {
  let sum = 0;
  for (let i = 0; i < n; i++) sum += i;
  return sum;
}

async runTask() {
  const res = await taskpool.execute(heavyCompute, 1000000);
  console.log('结果', res);
}
TaskPool 要点
  • @Concurrent标记并发函数。
  • 自动调度线程由池子管。
  • 返回 Promiseawait 拿结果。

Worker:独立线程

Worker 是一条长期存在的后台线程,跟主线程通过消息通信。适合需要持续工作的场景,比如长连接、大文件读写。

// 主线程
const worker = new worker.ThreadWorker('entry/ets/workers/my.ets');
worker.postMessage({ type: 'parse', data: raw });
worker.onmessage = (e) => { console.log('完成', e.data) };

Worker 是双向通信,来回发消息;TaskPool 是一次性任务池。

协程与异步

ArkTS 的 async/await 是单线程异步:I/O 等待时主线程不阻塞,等数据回来再继续。它不真正并行,但能让网络请求、读文件这类等待不卡界面。

鸿蒙并发:多个发光齿轮与任务队列节点并排运转、线程调度分发给子线程方块的蓝调插画
主线程调度任务,子线程方块并行跑重活。