#2023盲盒+码# worker概念及使用示例 原创

zhushangyuan_
发布于 2023-9-17 10:23
浏览
0收藏

【本文正在参加 2023「盲盒」+码有奖征文活动】,活动链接 https://ost.51cto.com/posts/25284

worker概念原理及使用示例

基本概念

#2023盲盒+码#  worker概念及使用示例-开源基础软件社区#2023盲盒+码#  worker概念及使用示例-开源基础软件社区

Worker是系统创建的一个单独线程,可以执行独立的耗时任务。创建Worker的线程称为宿主线程(不一定是主线程,工作线程也支持创建Worker子线程),Worker自身的线程称为Worker子线程(或Actor线程、工作线程)。每个Worker子线程与宿主线程都拥有独立的实例,包含基础设施、对象、代码段等。Worker子线程和宿主线程之间的通信是基于消息传递的,Worker通过序列化机制与宿主线程之间相互通信,完成命令及数据交互。

常用场景示例

那么在哪些场景下适合要使用Worker来实现并发呢?下面列举了两种场景:

  1. 运行时间超过3分钟的任务。例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker;

  2. 有关联的一系列同步任务。例如某数据库操作时,要用创建的句柄操作,包含增、删、改、查多个任务,要保证同一个句柄,需要使用Worker。

下面我们将使用视频下载的场景,来演示如何使用Worker。

场景预览图如下所示:

<img src=“images/worker_video.png” width=‘250’>

当视频过大时,可能会出现下载时长超过3分钟耗时的情况,因此我们使用Worker的方式来实现视频的下载,源码如下所示:

  1. 宿主线程创建一个worker线程;创建worker线程的方法:new worker.ThreadWorker();方法里面填写worker文件的路径,这里的worker文件路径和工程路径是无关的,主要是需要对照打包相对路径(moduleName + worker文件在ets下的路径),示例代码如下:
let workerInstance = new worker.ThreadWorker('entry/ets/pages/workers/worker.ts', {
        name: 'FriendsMoments Worker'
      });
  1. 宿主线程启动worker线程;启动通过postMessage方法来发送消息,里面可以传递自己需要的参数,这里传递的参数分别是应用上下文信息context、媒体数据地址mediaData以及判断图片数据和视频数据的标识isImageData。示例代码如下:
 workerInstance.postMessage({ context, mediaData: this.mediaData, isImageData: this.isImageData });
  1. worker线程监听宿主线程发送的消息;worker线程在onmessage中接收到宿主线程的postMessage请求,并通过request.downloadFile执行下载操作,将数据存储到本地。其中downloadTask.on(‘progress’)方法用来订阅下载任务进度,downloadTask.on(‘complete’)方法用来订阅下载任务完成,下载完成之后,通过workerPort.postMessage(true)来给宿主线程发送消息。
let workerPort = worker.workerPort;

workerPort.onmessage = async (e: MessageEvents) => {
  Logger.info('workerPort onmessage start');
  // worker线程接收主线程发送的信息
  let context = e.data.context;
  let filesDir = context.filesDir;
  let time = new Date().getTime();
  let filePath: string = '';
  let mediaDataUrl: string = '';
  // 数据处理
  if (e.data.isImageData) {
    let imageType: string = e.data.mediaData.split('.')[1];
    mediaDataUrl = `https://gitee.com/openharmony/applications_app_samples/raw/master/code/Solutions/IM/Chat/entry/src/main/ets${e.data.mediaData}`
    filePath = `${filesDir}/${time.toString()}.${imageType}`;
} else {
    filePath = `${filesDir}/${time.toString()}.mp4`;
    mediaDataUrl = e.data.mediaData;
    Logger.info('mst11 workerPort media filePath' + filePath);
}
try {
    request.downloadFile(context, {
        url: mediaDataUrl,
        filePath: filePath
    }).then((downloadTask) => {
      downloadTask.on('progress', (receivedSize: number, totalSize: number) => {
        Logger.info('receivedSize' + receivedSize + 'totalSize' + totalSize);
      })
      downloadTask.on('complete', () => {
        workerPort.postMessage(true);
        Logger.info('complete end');
      })
    }).catch((err) => {
        Logger.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
    });
} catch (err) {
    Logger.error(`mst11 Invoke downloadFile failed, code is ${err.code}, message is ${err.message}`);
}
}
  1. 宿主线程监听worker线程发送的信息;宿主线程通过onmessage接收到worker线程发送的消息,并执行下载的结果通知。示例代码如下:
 workerInstance.onmessage = (e: MessageEvents) => {
        if (e.data) {
          promptAction.showToast({ message: $r('app.string.download_successful'), duration: PROMPTACTION_DURATION });
        } else {
          promptAction.showToast({ message: $r('app.string.download_failed'), duration: PROMPTACTION_DURATION });
        }
      }

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
收藏
回复
举报
回复
    相关推荐