【高心星出品】
文章目錄
- 多線程Worker和@Sendable的使用方法
- 開發步驟
- 運行結果
多線程Worker和@Sendable的使用方法
Worker在HarmonyOS中提供了一種多線程的實現方式,它允許開發者在后臺線程中執行長耗時任務,從而避免阻塞主線程并提高應用的響應性。
@Sendable 注解主要用于標記那些需要在多線程環境中共享的數據對象或函數。被 @Sendable 標記的對象或函數可以在不同的線程之間高效地傳輸數據,這主要得益于 ArkTS 的序列化和反序列化機制。
開發步驟
【案例需求】 接下來要實現一個案例,創建兩個子線程,一個子線程負責數據求和,一個子線程負責數據相減,UI線程提供共享數據給這兩個子線程,子線程運行結果返回給UI線程。
-
創建兩個worker。
在ets/下創建一個workers目錄,在該目錄下創建worker。這兩個worker負責接受UI線程傳過來的數據,并且負責子線程運行實體,并將結果發送給UI線程。
- addworker的代碼
import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
import { Temp } from '../pages/Index';const workerPort: ThreadWorkerGlobalScope = worker.workerPort;/*** Defines the event handler to be called when the worker thread receives a message sent by the host thread.* The event handler is executed in the worker thread.** @param event message data*/
// 線程運行實體
function add(temp:Temp){let a=temp.alet b=temp.btemp.a+=5return a+b
}
// 子線程接受UI線程信息并處理
workerPort.onmessage = async (event: MessageEvents) => {if(event){// 模擬線程睡眠2sawait new Promise((resolve:(v:number)=>void)=>{setTimeout(()=>{resolve(10)},2000)})// 解析獲取ui線程發送的數據let t=event.data as Temp// 子線程向UI線程發送消息workerPort.postMessage(add(t))}
};/*** Defines the event handler to be called when the worker receives a message that cannot be deserialized.* The event handler is executed in the worker thread.** @param event message data*/
workerPort.onmessageerror = (event: MessageEvents) => {
};/*** Defines the event handler to be called when an exception occurs during worker execution.* The event handler is executed in the worker thread.** @param event error message*/
workerPort.onerror = (event: ErrorEvent) => {
};
- jianworker的代碼
import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
import { Temp } from '../pages/Index';const workerPort: ThreadWorkerGlobalScope = worker.workerPort;/*** Defines the event handler to be called when the worker thread receives a message sent by the host thread.* The event handler is executed in the worker thread.** @param event message data*/
// 線程運行實體
function jian(t:Temp){let a=t.alet b=t.bt.a-=5return Math.abs(a-b)
}
// 子線程接受UI線程的信息 并運行
workerPort.onmessage = async (event: MessageEvents) => {if(event){// 模擬線程睡眠2sawait new Promise((resolve:(v:string)=>void)=>{setTimeout(()=>{resolve('a')},2000)})let t=event.data as Temp// 向UI線程發送消息workerPort.postMessage(jian(t))}
};/*** Defines the event handler to be called when the worker receives a message that cannot be deserialized.* The event handler is executed in the worker thread.** @param event message data*/
workerPort.onmessageerror = (event: MessageEvents) => {
};/*** Defines the event handler to be called when an exception occurs during worker execution.* The event handler is executed in the worker thread.** @param event error message*/
workerPort.onerror = (event: ErrorEvent) => {
};
- Index.ets代碼
import { MessageEvents, worker } from "@kit.ArkTS";@Sendable
export class Temp {a: numberb: numberconstructor(a: number, b: number) {this.a = a;this.b = b;}
}
@Entry
@Component
struct Index {@State message: string = 'Hello World';// UI線程和其他兩個子線程共享的數據private temp = new Temp(10, 20)//創建了兩個線程private addthread = new worker.ThreadWorker('entry/ets/workers/addworker.ets')private jianthread = new worker.ThreadWorker('entry/ets/workers/jianworker.ets')aboutToAppear(): void {// UI線程中接受兩個子線程發送的信息this.addthread.onmessage = (event: MessageEvents) => {console.log('gxxt add ', event.data as number)console.log('gxxt 當前的temp值: ',JSON.stringify(this.temp))}this.jianthread.onmessage = (event: MessageEvents) => {console.log('gxxt jian ', event.data as number)console.log('gxxt 當前的temp值: ',JSON.stringify(this.temp))}}build() {Column({ space: 20 }) {Button('加線程').width('60%').onClick(() => {this.addthread.postMessageWithSharedSendable(this.temp)})Button('減線程').width('60%').onClick(() => {this.jianthread.postMessageWithSharedSendable(this.temp)})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}
項目通過點擊兩個按鈕啟動兩個線程,并將共享數據temp發送給兩個子線程,兩個子線程分別執行相加和相減,同時還更新共享數據的原始值,通過觀察運算結果和共享數據的變化,我們能掌握worker的開發方式。
運行結果
02-28 09:10:59.798 3292-3292 A03d00/JSAPP com.gxx.workdemo I gxxt add運算結果: 30
02-28 09:10:59.799 3292-3292 A03d00/JSAPP com.gxx.workdemo I gxxt 當前的temp值: {"a":15,"b":20}
02-28 09:11:04.877 3292-3292 A03d00/JSAPP com.gxx.workdemo I gxxt jian運算結果 5
02-28 09:11:04.877 3292-3292 A03d00/JSAPP com.gxx.workdemo I gxxt 當前的temp值: {"a":10,"b":20}
剛一開始進行運算的時候add線程面對的a為10,b為20,計算結果為30,add線程同時a=a+5操作,所以此時UI線程得到的a為15;然后jian線程運行結果為|15-20|,jian線程同時a=a-5,所以此時UI線程得到的a為10.