
回复
【本文正在参加 2023「盲盒」+码有奖征文活动】,活动链接 https://ost.51cto.com/posts/25284
Worker是系统创建的一个单独线程,可以执行独立的耗时任务。创建Worker的线程称为宿主线程(不一定是主线程,工作线程也支持创建Worker子线程),Worker自身的线程称为Worker子线程(或Actor线程、工作线程)。每个Worker子线程与宿主线程都拥有独立的实例,包含基础设施、对象、代码段等。Worker子线程和宿主线程之间的通信是基于消息传递的,Worker通过序列化机制与宿主线程之间相互通信,完成命令及数据交互。
那么在哪些场景下适合要使用Worker来实现并发呢?下面列举了两种场景:
运行时间超过3分钟的任务。例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker;
有关联的一系列同步任务。例如某数据库操作时,要用创建的句柄操作,包含增、删、改、查多个任务,要保证同一个句柄,需要使用Worker。
下面我们将使用视频下载的场景,来演示如何使用Worker。
场景预览图如下所示:
<img src=“images/worker_video.png” width=‘250’>
当视频过大时,可能会出现下载时长超过3分钟耗时的情况,因此我们使用Worker的方式来实现视频的下载,源码如下所示:
let workerInstance = new worker.ThreadWorker('entry/ets/pages/workers/worker.ts', {
name: 'FriendsMoments Worker'
});
workerInstance.postMessage({ context, mediaData: this.mediaData, isImageData: this.isImageData });
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}`);
}
}
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 });
}
}