在这里插入图片描述

摘要

端侧超分(Super Resolution)功能上线后,连续处理多张老照片或在滑动预览场景中挂载超分,手机后盖明显发烫、约 30 秒后预览掉帧、超分输出反而变慢——根因是 NPU 持续满负载触发系统温控降频,撞上了端侧 AI 推理最典型的"功耗墙"。本文基于 HarmonyOS 的 @kit.CoreVisionKit 超分能力,结合 @ohos.thermal 温控订阅与 @ohos.batteryInfo 充电状态感知,落地三招:帧率节流、温控订阅降档、分片推理。实测连续处理 50 张 1080p 图片,机身温度峰值从 46℃ 降到 39℃,全程无掉帧,平均单张耗时 230ms。文中给出可直接复用的 TypeScript 代码骨架、整体调度流程图、温控档位与并发度对照表,以及上线前必查的实战清单。

目录

一、背景与痛点

上篇讲了端侧超分怎么接入,但功能上线后我碰到更隐蔽的问题:用户连续放大十几张老照片,或把超分挂在有滑动预览的场景里,手机后盖明显发烫,约 30 秒后预览开始掉帧,超分输出反而变慢。查日志发现是 NPU 持续满负载触发了系统温控(thermal)降频——这正是端侧 AI 推理最典型的"功耗墙"。

问题本质不是模型不准,而是没有给推理任务做节流和温控感知。超分是重负载算子,若在主线程或高优先级循环里无脑狂跑,不仅伤体验,长期还会加速电池老化、招来投诉。本文把我在项目里落地的三招——帧率节流、温控订阅降档、分片推理——完整讲清。

二、环境与能力规格

维度规格
超分能力@kit.CoreVisionKit 的 imageSuperResolution(API 26)
温控接口@ohos.thermal 的 ThermalManager,订阅 levelChange
功耗接口@ohos.batteryInfo 读取电量/充电状态
运行位置端侧 NPU/XPU,数据不出设备
适配建议推理放 TaskPool,避免阻塞 UI 线程

系统温控分 0~4 级(NORMAL/LOW/WARNING/CRITICAL/EMERGENCY),我们只在 NORMAL/LOW 跑满速,WARNING 起主动降速。

三、核心代码(可复用骨架)

import { imageSuperResolution } from '@kit.CoreVisionKit';
import { thermal } from '@ohos.thermal';
import { batteryInfo } from '@ohos.batteryInfo';
import { taskpool } from '@kit.ArkTS';

// 1) 订阅温控,动态决定推理并发度
let thermalLevel = 0; // 0=NORMAL
thermal.on('levelChange', (level: number) => {
  thermalLevel = level;
  console.info(`[SR] thermal level -> ${level}`);
});

// 2) 根据温控档位推导每批最多处理几张
function batchSizeByThermal(): number {
  if (thermalLevel <= 1) return 4;   // NORMAL/LOW:满速
  if (thermalLevel === 2) return 2;  // WARNING:减半
  return 1;                          // CRITICAL+:单张串行
}

// 3) 是否处于充电状态(充电时温控更宽松,可放开并发)
function isCharging(): boolean {
  return batteryInfo.chargingStatus === batteryInfo.ChargingStatus.ENABLE;
}

// 4) 综合温控与充电状态,得到最终并发度
function effectiveConcurrency(): number {
  const base = batchSizeByThermal();
  return isCharging() ? Math.min(base + 1, 4) : base;
}

// 5) 页面级单例 Analyzer,避免反复 create/destroy 带来的额外发热
let analyzer: imageSuperResolution.ImageSRAnalyzer | null = null;

async function getAnalyzer(): Promise<imageSuperResolution.ImageSRAnalyzer> {
  if (analyzer === null) {
    analyzer = await imageSuperResolution.ImageSRAnalyzer.create();
  }
  return analyzer;
}

// 6) 单张超分放到 TaskPool,远离 UI 线程
async function srOne(visionImage: object): Promise<ArrayBuffer> {
  return await taskpool.execute(async () => {
    const sr = await getAnalyzer();
    return await sr.process(visionImage);
  });
}

// 7) 分片推理:按当前并发度分批处理,批间让出调度
async function srBatch(images: object[]): Promise<ArrayBuffer[]> {
  const results: ArrayBuffer[] = [];
  let index = 0;
  while (index < images.length) {
    const size = effectiveConcurrency();
    const slice = images.slice(index, index + size);
    const part = await Promise.all(slice.map((img) => srOne(img)));
    results.push(...part);
    index += size;
    // 批间短暂让出,给系统降温与调度留出窗口
    await new Promise<void>((resolve) => setTimeout(resolve, 16));
  }
  return results;
}

// 8) 页面销毁时释放单例并取消订阅,避免泄漏
function releaseSR(): void {
  thermal.off('levelChange');
  if (analyzer !== null) {
    analyzer.destroy();
    analyzer = null;
  }
}

四、整体流程与温控档位说明

先看整体调度流程:从图片入队到按温控档位分批推理,再到批间让出与资源释放。

是

否

是

否

图片入队 srBatch()

读取 thermalLevel

是否充电中

并发度 +1(上限 4)

按档位取并发度

切片并 Promise.all 推理

TaskPool 内复用单例 Analyzer

批间 setTimeout 16ms 让出

还有剩余图片

返回结果数组

页面销毁 releaseSR()

温控档位与策略对应关系如下,可直接对照代码里的 batchSizeByThermal():

温控档位level并发度策略说明
NORMAL04满速运行,正常批量修复
LOW14仍满速,但已接近阈值需关注
WARNING22并发减半,优先保体验
CRITICAL31单张串行,避免持续满负载
EMERGENCY41单张串行,必要时提示用户暂停

五、运行效果与踩坑

  • 踩坑 1:Analyzer 反复 create/destroy 反而更热。 我一开始每张都新建,初始化开销比推理还大。改成"页面级单例 + 用完复用"后,单张平均耗时从 480ms 降到 210ms,温升更平缓。
  • 踩坑 2:thermal 回调不在主线程。 直接拿 level 改 UI 状态会崩,必须用 taskpool 或 @State 配合切回。
  • 踩坑 3:充电时温控更宽松。 实测插电状态同一负载 level 长期停在 1,所以"批量修复相册"功能我默认提示用户插电运行,体验最佳。
  • 效果: 连续处理 50 张 1080p 图,机身温度峰值从 46℃ 降到 39℃,无掉帧,平均单张 230ms。

六、小结与适用边界

端侧超分不是"调通 API 就完事",功耗与温控是上线前必须过的关。核心思路:推理异步化 + 温控感知降档 + 充电视为加速条件。适合老照片修复、相册实时预览;不适合对单张时延极度敏感、且设备无 NPU 的低端机。

七、实战清单(可直接抄)

  • 推理统一放 TaskPool,页面级单例复用 Analyzer,严禁逐张 create/destroy,单张耗时能从 480ms 压到 210ms。
  • 启动即订阅 @ohos.thermal 的 levelChange,WARNING 起自动降并发(4→2→1),把温升主动权交给系统。
  • 批量任务主动提示用户插电运行,实测插电时温控档位更宽松、连跑不掉速。
  • 上线前用 50 张图连跑画温度曲线,峰值控在 40℃ 内、全程无掉帧再发布。
  • 低端无 NPU 设备提供"关闭超分"开关,避免负体验,也防止无谓耗电。

说到底,端侧 AI 的体验门槛从来不是"能不能跑",而是"跑得稳不稳、凉不凉"。把温控和功耗当成一等公民,超分才从 Demo 变成能天天用的功能。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐