日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

OpenHarmony的ArkUI應(yīng)用開(kāi)發(fā)框架提供了Worker和Taskpool等支持后臺(tái)多線程任務(wù)的方式,本文會(huì)通過(guò)開(kāi)發(fā)范例介紹Worker的使用。在ArkUI應(yīng)用開(kāi)發(fā)中,有2類線程:宿主線程和Worker線程。

概念介紹

在和應(yīng)用界面進(jìn)行交互操作時(shí),如按鈕點(diǎn)擊、屏幕滑動(dòng),想同時(shí)執(zhí)行一些耗時(shí)的操作,如網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)下載。在應(yīng)用開(kāi)發(fā)中,通常使用UI線程和后臺(tái)線程來(lái)分別處理這些操作,UI線程主要負(fù)責(zé)處理UI事件和用戶交互操作,后臺(tái)線程負(fù)責(zé)耗時(shí)操作。通過(guò)創(chuàng)建后臺(tái)線程可以避免UI線程被阻塞,提高應(yīng)用程序的響應(yīng)速度和用戶體驗(yàn)。

OpenHarmony的ArkUI應(yīng)用開(kāi)發(fā)框架提供了Worker和Taskpool等支持后臺(tái)多線程任務(wù)的方式,本文會(huì)通過(guò)開(kāi)發(fā)范例介紹Worker的使用。在ArkUI應(yīng)用開(kāi)發(fā)中,有2類線程:宿主線程和Worker線程。創(chuàng)建Worker的線程被稱為宿主線程,Worker腳本程序工作的線程被稱為Worker線程。Worker線程是與主線程并行的獨(dú)立線程,通常在Worker線程中處理耗時(shí)的操作。需要注意的是,在Worker后臺(tái)線程中執(zhí)行的代碼不能直接修改UI元素,UI元素的更新必須發(fā)生在UI線程中。

API接口

ArkUI的Worker線程模塊提供了構(gòu)造函數(shù)接口用于創(chuàng)建Worker線程,并為UI線程和Worker線程提供了線程間通訊接口。關(guān)于Worker API能力詳細(xì)信息,請(qǐng)參考@ohos.worker。本節(jié)只進(jìn)行關(guān)鍵接口解讀。

宿主線程中的構(gòu)造函數(shù)

使用Worker的接口方法前,需要先構(gòu)造ThreadWorker實(shí)例,ThreadWorker類繼承WorkerEventTarget。

注意:Worker還提供構(gòu)造函數(shù)worker.Worker(scriptURL: string, options?: WorkerOptions),由于已經(jīng)標(biāo)記廢棄,請(qǐng)避免使用該廢棄的接口。

ThreadWorker構(gòu)造函數(shù)如下:

constructor(scriptURL: string, options?: WorkerOptions)

其中,參數(shù)解釋:

參數(shù)名

類型

必填

說(shuō)明

scriptURL

string

Worker執(zhí)行腳本的路徑

options

WorkerOptions

Worker構(gòu)造的選項(xiàng)。

我們來(lái)看一個(gè)構(gòu)造的示例。不用擔(dān)心其中的腳步文件如何編寫(xiě),使用DevEco Studio創(chuàng)建Worker文件的時(shí)候,會(huì)生成模板。

import worker from '@ohos.worker';
// worker線程創(chuàng)建

// Stage模型-目錄同級(jí)(entry模塊下,workers目錄與pages目錄同級(jí))
const workerStageModel01 = new worker.ThreadWorker('entry/ets/workers/worker.ts', {name:"first worker in Stage model"});
// Stage模型-目錄不同級(jí)(entry模塊下,workers目錄是pages目錄的子目錄)
const workerStageModel02 = new worker.ThreadWorker('entry/ets/pages/workers/worker.ts');

宿主線程中發(fā)送消息

宿主線程通過(guò)轉(zhuǎn)移對(duì)象所有權(quán)或者拷貝數(shù)據(jù)的方式向Worker線程發(fā)送消息,提供了兩個(gè)postMessage<sup>9+</sup>接口,其中一個(gè)如下所示:

postMessage(message: Object, options?: PostMessageOptions): void

其中,參數(shù)如下:

參數(shù)名

類型

必填

說(shuō)明

message

Object

發(fā)送至Worker的數(shù)據(jù),該數(shù)據(jù)對(duì)象必須是可序列化。

options

PostMessageOptions

當(dāng)填入該參數(shù)時(shí),與傳入ArrayBuffer[]的作用一致,該數(shù)組中對(duì)象的所有權(quán)會(huì)被轉(zhuǎn)移到Worker線程,

在宿主線程中將會(huì)變?yōu)椴豢捎茫瑑H在Worker線程中可用。

若不填入該參數(shù),默認(rèn)設(shè)置為 undefined,通過(guò)拷貝數(shù)據(jù)的方式傳輸信息到Worker線程。

示例代碼如下:

const workerInstance = new worker.ThreadWorker("entry/ets/workers/worker.ts");

workerInstance.postMessage("hello world");

var buffer = new ArrayBuffer(8);
workerInstance.postMessage(buffer, [buffer]);

宿主線程中監(jiān)聽(tīng)消息

在宿主線程中,通過(guò)監(jiān)聽(tīng)事件來(lái)處理接收到的Worker線程中的消息。worker模塊提供了若干監(jiān)聽(tīng)接口,我們以onmessage為例進(jìn)行講解,其他監(jiān)聽(tīng)方式類似,可以參考API參考文檔,不再贅述。
Worker對(duì)象的onmessage屬性表示宿主線程接收到來(lái)自其創(chuàng)建的Worker通過(guò)parentPort.postMessage接口發(fā)送的消息時(shí)被調(diào)用的事件處理程序,處理程序在宿主線程中執(zhí)行。

onmessage?: (event: MessageEvents) => void

其中,參數(shù)如下:

參數(shù)名

類型

必填

說(shuō)明

event

MessageEvents

收到的Worker消息數(shù)據(jù)。

示例代碼如下:

const workerInstance = new worker.ThreadWorker("entry/ets/workers/worker.ts");
workerInstance.onmessage = function(e) {
    // e : MessageEvents, 用法如下:
    // let data = e.data;
    console.log("onmessage");
}

Worker線程中構(gòu)造實(shí)例

ThreadWorkerGlobalScope是Worker線程用于與宿主線程通信的類,通過(guò)postMessage接口發(fā)送消息給宿主線程、通過(guò)close接口銷毀Worker線程。ThreadWorkerGlobalScope類繼承GlobalScope9+。

注意:Worker還提供worker.parentPort接口,該接口屬于廢棄接口,應(yīng)避免使用。

在Worker腳本文件中,如entrysrcmAInetsworkersWorker.ts,構(gòu)建實(shí)例如下:

import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker';

var workerPort: ThreadWorkerGlobalScope = worker.workerPort;

Worker線程中監(jiān)聽(tīng)消息

ThreadWorkerGlobalScope的onmessage屬性表示W(wǎng)orker線程收到來(lái)自其宿主線程通過(guò)postMessage接口發(fā)送的消息時(shí)被調(diào)用的事件處理程序,處理程序在Worker線程中執(zhí)行。

onmessage?: (this: ThreadWorkerGlobalScope, ev: MessageEvents) => void

其中,參數(shù)如下所示:

參數(shù)名

類型

必填

說(shuō)明

this

ThreadWorkerGlobalScope

指向調(diào)用者對(duì)象。

ev

MessageEvents

收到宿主線程發(fā)送的數(shù)據(jù)。

示例代碼如下:

// main thread
import worker from '@ohos.worker';
const workerInstance = new worker.ThreadWorker("entry/ets/workers/worker.ts");
workerInstance.postMessage("hello world");
 
// worker.ts
import worker from '@ohos.worker';
const workerPort = worker.workerPort;
workerPort.onmessage = function(e) {
    console.log("receive main thread message");
}

Worker線程中發(fā)送消息

Worker線程通過(guò)轉(zhuǎn)移對(duì)象所有權(quán)或者拷貝數(shù)據(jù)的方式向宿主線程發(fā)送消息。提供了兩個(gè)postMessage9+接口,其中一個(gè)如下所示:

postMessage(messageObject: Object, options?: PostMessageOptions): void

其中,參數(shù)如下所示:

參數(shù)名

類型

必填

說(shuō)明

message

Object

發(fā)送至宿主線程的數(shù)據(jù),該數(shù)據(jù)對(duì)象必須是可序列化,序列化支持類型見(jiàn)其他說(shuō)明。

options

PostMessageOptions

當(dāng)填入該參數(shù)時(shí),與傳入ArrayBuffer[]的作用一致,該數(shù)組中對(duì)象的所有權(quán)會(huì)被轉(zhuǎn)移到宿主線程,在Worker線程中將會(huì)變?yōu)椴豢捎茫瑑H在宿主線程中可用。<br/>若不填入該參數(shù),默認(rèn)設(shè)置為 undefined,通過(guò)拷貝數(shù)據(jù)的方式傳輸信息到宿主線程。

線程的關(guān)閉和銷毀

銷毀worker的方式有兩種;

  • 被動(dòng)銷毀

worker線程的生命周期跟隨應(yīng)用。若應(yīng)用退出則釋放worker資源。worker線程在執(zhí)行過(guò)程中出現(xiàn)異常終止掉worker。

  • 主動(dòng)銷毀

主動(dòng)銷毀worker的方式有兩種,第一種在宿主線程調(diào)用worker.terminate();第二種在worker線程調(diào)用workerPort.close()。 worker銷毀前會(huì)觸發(fā)onexit回調(diào),注意,onexit回調(diào)只會(huì)在宿主線程中執(zhí)行。

宿主線程中銷毀worker線程的示例代碼:

const worker = new worker.ThreadWorker("entry/ets/workers/worker.ts");
worker.terminate();

Worker線程中銷毀worker線程的示例代碼:

// worker.ts
import worker from '@ohos.worker';
const workerPort = worker.workerPort;
workerPort.onmessage = function(e) {
    workerPort.close()
}

實(shí)現(xiàn)場(chǎng)景

我們模擬一個(gè)簡(jiǎn)單的UI線程和Worker線程交互的場(chǎng)景。UI線程發(fā)送一個(gè)簡(jiǎn)單的消息給Worker線程,觸發(fā)Worker線程中的一個(gè)耗時(shí)模擬操作,然后把結(jié)果返回UI線程進(jìn)行界面展示。有點(diǎn)像,一個(gè)人站在山谷前,大喊一聲,過(guò)一段時(shí)間會(huì)從山谷中返回聲音。這個(gè)人就是UI線程,返回回音的山谷就是后臺(tái)線程。

設(shè)計(jì)思路

對(duì)于UI線程,只需要簡(jiǎn)單地包含一個(gè)text和一個(gè)button。text用于展示后臺(tái)線程返回的信息,button按鈕被點(diǎn)擊后向后臺(tái)線程發(fā)送消息。UI線程還需要處理后臺(tái)返回的消息。

對(duì)于后臺(tái)線程,需要處理接收到UI消息,模擬一個(gè)耗時(shí)操作,然后返回。實(shí)現(xiàn)效果如下:

發(fā)送消息前

等待返回

消息返回

多線程任務(wù)開(kāi)發(fā)范例-Worker-開(kāi)源基礎(chǔ)軟件社區(qū)多線程任務(wù)開(kāi)發(fā)范例-Worker-開(kāi)源基礎(chǔ)軟件社區(qū)

多線程任務(wù)開(kāi)發(fā)范例-Worker-開(kāi)源基礎(chǔ)軟件社區(qū)多線程任務(wù)開(kāi)發(fā)范例-Worker-開(kāi)源基礎(chǔ)軟件社區(qū)

多線程任務(wù)開(kāi)發(fā)范例-Worker-開(kāi)源基礎(chǔ)軟件社區(qū)多線程任務(wù)開(kāi)發(fā)范例-Worker-開(kāi)源基礎(chǔ)軟件社區(qū)

開(kāi)發(fā)步驟

創(chuàng)建Worker

DevEco Studio提供了非常方便的創(chuàng)建Worker的方法。

在DevEco Studio工程中,選擇entry,右鍵菜單選擇New-Worker,輸入Worker名稱即可,比如就使用默認(rèn)的Worker。

Studio會(huì)自動(dòng)為生成文件entrysrcmainetsworkersWorker.ts,并在模塊級(jí)配置文件entrybuild-profile.json5中添加workers配置,如圖所示,可以看出使用的相對(duì)路徑:‘./src/main/ets/workers/Worker.ts’。

文件entrybuild-profile.json5片段:

"buildOption": {
    "sourceOption": {
      "workers": [
        './src/main/ets/workers/Worker.ts',
      ]
    }
  },

宿主進(jìn)程代碼實(shí)現(xiàn)

我們先看下宿主進(jìn)程中,代碼如何實(shí)現(xiàn)。

我們知道,Worker線程不可以直接操作UI。在宿主線程中,監(jiān)聽(tīng)到的worker線程返回消息無(wú)法直接賦值給@State變量進(jìn)行UI界面渲染的。需要通過(guò)其他方式進(jìn)行傳值,本示例中我們使用AppStorage和@Watch裝飾器。

如代碼所示,創(chuàng)建一個(gè)workerResult變量,當(dāng)該變量發(fā)生變化后,會(huì)通過(guò)執(zhí)行監(jiān)聽(tīng)函數(shù)workerResultChanged(),把存儲(chǔ)的值賦值給@State變量。

在宿主線程中創(chuàng)建的worker實(shí)例為threadWorker,它負(fù)責(zé)通過(guò)腳本文件創(chuàng)建worker線程,并負(fù)責(zé)執(zhí)行和worker線程的通訊交互。

在宿主線程中,界面中包含一個(gè)文本,展示文字,如果從worker進(jìn)程中接收到的消息等,還有一個(gè)按鈕,點(diǎn)擊時(shí)會(huì)觸發(fā)發(fā)worker線程發(fā)送消息。

在Button的onClick()函數(shù)中,主要實(shí)現(xiàn)了2個(gè)功能,一個(gè)是定義宿主線程接收到worker消息的回調(diào)函數(shù)。從代碼中可以看出,當(dāng)接收到消息后,會(huì)保存到AppStorage里。

另外一個(gè)功能點(diǎn)是,通過(guò)調(diào)用postMessage接口,向worker線程發(fā)送消息。

在宿主線程中,還支持很多監(jiān)聽(tīng)函數(shù),限于篇幅,不再展示,可以參考API自行實(shí)現(xiàn)。

import worker from '@ohos.worker';
let workerResult = AppStorage.Link('workerResult')

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'
  @StorageLink('workerResult') @Watch('workerResultChanged') workerResult: String = ''
  threadWorker: worker.ThreadWorker = new worker.ThreadWorker("entry/ets/workers/Worker.ts")

  workerResultChanged() {
    this.message = AppStorage.Get('workerResult')
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        Button('Click').onClick(
          () => {
            this.threadWorker.onmessage = function (message) {
              AppStorage.Set<String>('workerResult', message.data)
            }
            this.threadWorker.postMessage("message from main thread.")
          }
        )
      }
      .width('100%')
    }
    .height('100%')
  }
}

Worker進(jìn)程代碼實(shí)現(xiàn)

我們?cè)倏聪耊orker進(jìn)程中,代碼如何實(shí)現(xiàn)。Work線程腳本文件entrysrcmainetsworkersWorker.ts。

語(yǔ)句var workerPort: ThreadWorkerGlobalScope = worker.workerPort;用于構(gòu)建Worker線程中的實(shí)例對(duì)象,該實(shí)例可以與宿主線程進(jìn)行消息交互。

在workerPort.onmessage監(jiān)聽(tīng)函數(shù)中,控制臺(tái)打印輸出從宿主線程中接收到的消息,然后通過(guò)workerPort.postMessage接口向宿主線程第一次發(fā)送消息,告訴宿主線程
請(qǐng)等待worker線程的操作。

然后,使用setTimeout函數(shù)模擬一個(gè)耗時(shí)操作,5000ms后再次向宿主線程發(fā)送消息,攜帶一個(gè)隨機(jī)數(shù)字,用于區(qū)分多次返回消息的差異。

在worker線程中的其他監(jiān)聽(tīng)函數(shù),如workerPort.onmessageerror、workerPort.onerror,或者銷毀worker線程的操作可以參考API自行實(shí)現(xiàn)。

文件entrysrcmainetsworkersWorker.ts片段:

import worker from '@ohos.worker';
import { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker';

var workerPort: ThreadWorkerGlobalScope = worker.workerPort;

workerPort.onmessage = function (e: MessageEvents) {
  console.info("onmessage: " + e.data)
  workerPort.postMessage("Waiting for the worker ...")
  setTimeout(() => {
    console.info('send to main thread')
    workerPort.postMessage("Echo from worker Random: " 
    + Math.round(100 * Math.random()))
  },
    5000)
}

運(yùn)行測(cè)試效果

代碼編寫(xiě)完畢,可以測(cè)試運(yùn)行查看效果。推薦在模塊級(jí)配置文件entrybuild-profile.json5中,修改運(yùn)行時(shí)為"HarmonyOS",這樣就可以在DevEco Studio中使用Simulator模擬器進(jìn)行運(yùn)行測(cè)試,手頭沒(méi)有設(shè)備也可以輕松體驗(yàn)OpenHarmony應(yīng)用開(kāi)發(fā)。

注意事項(xiàng)

Worker線程不可以直接操作UI,@State等變量無(wú)法直接進(jìn)行賦值渲染,需要通過(guò)其他方式進(jìn)行傳值。在本開(kāi)發(fā)范例中, 就借助了AppStorage。

Worker線程不使用時(shí),請(qǐng)及時(shí)銷毀,避免耗用資源。Worker有資源限制,如果創(chuàng)建數(shù)量太多,可以報(bào)如下錯(cuò)誤:

Error message: Worker initialization failure, the number of workers exceeds the maximum.
SourceCode:
this.threadWorker = new worker.ThreadWorker("entry/ets/workers/Worker.ts");

分享到:
標(biāo)簽:多線程
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定