TaskPool和Worker的對(duì)比

2024-02-16 13:44 更新

TaskPool(任務(wù)池)和Worker的作用是為應(yīng)用程序提供一個(gè)多線程的運(yùn)行環(huán)境,用于處理耗時(shí)的計(jì)算任務(wù)或其他密集型任務(wù)??梢杂行У乇苊膺@些任務(wù)阻塞主線程,從而最大化系統(tǒng)的利用率,降低整體資源消耗,并提高系統(tǒng)的整體性能。

本文將從實(shí)現(xiàn)特點(diǎn)適用場(chǎng)景兩個(gè)方面來(lái)進(jìn)行TaskPool與Worker的比較,同時(shí)提供了各自運(yùn)作機(jī)制和注意事項(xiàng)的相關(guān)說(shuō)明。

實(shí)現(xiàn)特點(diǎn)對(duì)比

表1 TaskPool和Worker的實(shí)現(xiàn)特點(diǎn)對(duì)比

實(shí)現(xiàn)

TaskPool

Worker

內(nèi)存模型

線程間隔離,內(nèi)存不共享。

線程間隔離,內(nèi)存不共享。

參數(shù)傳遞機(jī)制

采用標(biāo)準(zhǔn)的結(jié)構(gòu)化克隆算法(Structured Clone)進(jìn)行序列化、反序列化,完成參數(shù)傳遞。

支持ArrayBuffer轉(zhuǎn)移和SharedArrayBuffer共享。

采用標(biāo)準(zhǔn)的結(jié)構(gòu)化克隆算法(Structured Clone)進(jìn)行序列化、反序列化,完成參數(shù)傳遞。

支持ArrayBuffer轉(zhuǎn)移和SharedArrayBuffer共享。

參數(shù)傳遞

直接傳遞,無(wú)需封裝,默認(rèn)進(jìn)行transfer。

消息對(duì)象唯一參數(shù),需要自己封裝。

方法調(diào)用

直接將方法傳入調(diào)用。

在Worker線程中進(jìn)行消息解析并調(diào)用對(duì)應(yīng)方法。

返回值

異步調(diào)用后默認(rèn)返回。

主動(dòng)發(fā)送消息,需在onmessage解析賦值。

生命周期

TaskPool自行管理生命周期,無(wú)需關(guān)心任務(wù)負(fù)載高低。

開(kāi)發(fā)者自行管理Worker的數(shù)量及生命周期。

任務(wù)池個(gè)數(shù)上限

自動(dòng)管理,無(wú)需配置。

同個(gè)進(jìn)程下,最多支持同時(shí)開(kāi)啟8個(gè)Worker線程。

任務(wù)執(zhí)行時(shí)長(zhǎng)上限

無(wú)限制。

無(wú)限制。

設(shè)置任務(wù)的優(yōu)先級(jí)

不支持。

不支持。

執(zhí)行任務(wù)的取消

支持取消任務(wù)隊(duì)列中等待的任務(wù)。

不支持。

適用場(chǎng)景對(duì)比

TaskPool偏向獨(dú)立任務(wù)維度,該任務(wù)在線程中執(zhí)行,無(wú)需關(guān)注線程的生命周期,超長(zhǎng)任務(wù)(大于3分鐘)會(huì)被系統(tǒng)自動(dòng)回收;而Worker偏向線程的維度,支持長(zhǎng)時(shí)間占據(jù)線程執(zhí)行,需要主動(dòng)管理線程生命周期。

常見(jiàn)的一些開(kāi)發(fā)場(chǎng)景及適用具體說(shuō)明如下:

  • 有關(guān)聯(lián)的一系列同步任務(wù)。例如在一些需要?jiǎng)?chuàng)建、使用句柄的場(chǎng)景中,句柄創(chuàng)建每次都是不同的,該句柄需永久保存,保證使用該句柄進(jìn)行操作,需要使用Worker。
  • 需要頻繁取消的任務(wù)。例如圖庫(kù)大圖瀏覽場(chǎng)景,為提升體驗(yàn),會(huì)同時(shí)緩存當(dāng)前圖片左右側(cè)各2張圖片,往一側(cè)滑動(dòng)跳到下一張圖片時(shí),要取消另一側(cè)的一個(gè)緩存任務(wù),需要使用TaskPool。
  • 大量或者調(diào)度點(diǎn)較分散的任務(wù)。例如大型應(yīng)用的多個(gè)模塊包含多個(gè)耗時(shí)任務(wù),不方便使用8個(gè)Worker去做負(fù)載管理,推薦采用TaskPool。

TaskPool運(yùn)作機(jī)制

圖1 TaskPool運(yùn)作機(jī)制示意圖

TaskPool支持開(kāi)發(fā)者在主線程封裝任務(wù)拋給任務(wù)隊(duì)列,系統(tǒng)選擇合適的工作線程,進(jìn)行任務(wù)的分發(fā)及執(zhí)行,再將結(jié)果返回給主線程。接口直觀易用,支持任務(wù)的執(zhí)行、取消。工作線程數(shù)量上限為4。

Worker運(yùn)作機(jī)制

圖2 Worker運(yùn)作機(jī)制示意圖

創(chuàng)建Worker的線程稱(chēng)為宿主線程(不一定是主線程,工作線程也支持創(chuàng)建Worker子線程),Worker自身的線程稱(chēng)為Worker子線程(或Actor線程、工作線程)。每個(gè)Worker子線程與宿主線程擁有獨(dú)立的實(shí)例,包含基礎(chǔ)設(shè)施、對(duì)象、代碼段等。Worker子線程和宿主線程之間的通信是基于消息傳遞的,Worker通過(guò)序列化機(jī)制與宿主線程之間相互通信,完成命令及數(shù)據(jù)交互。

TaskPool注意事項(xiàng)

  • 實(shí)現(xiàn)任務(wù)的函數(shù)需要使用裝飾器@Concurrent標(biāo)注,且僅支持在.ets文件中使用。

  • 實(shí)現(xiàn)任務(wù)的函數(shù)入?yún)⑿铦M足序列化支持的類(lèi)型,詳情請(qǐng)參見(jiàn)數(shù)據(jù)傳輸對(duì)象

  • 由于不同線程中上下文對(duì)象是不同的,因此TaskPool工作線程只能使用線程安全的庫(kù),例如UI相關(guān)的非線程安全庫(kù)不能使用。

  • 序列化傳輸?shù)臄?shù)據(jù)量大小限制為16MB。

Worker注意事項(xiàng)

  • 創(chuàng)建Worker時(shí),傳入的Worker.ts路徑在不同版本有不同的規(guī)則,詳情請(qǐng)參見(jiàn)文件路徑注意事項(xiàng)。

  • Worker創(chuàng)建后需要手動(dòng)管理生命周期,且最多同時(shí)運(yùn)行的Worker子線程數(shù)量為8個(gè),詳情請(qǐng)參見(jiàn)生命周期注意事項(xiàng)。

  • Ability類(lèi)型的Module支持使用Worker,Library類(lèi)型的Module不支持使用Worker。

  • 創(chuàng)建Worker不支持使用其他Module的Worker.ts文件,即不支持跨模塊調(diào)用Worker。

  • 由于不同線程中上下文對(duì)象是不同的,因此Worker線程只能使用線程安全的庫(kù),例如UI相關(guān)的非線程安全庫(kù)不能使用。

  • 序列化傳輸?shù)臄?shù)據(jù)量大小限制為16MB。

文件路徑注意事項(xiàng)

當(dāng)使用Worker模塊具體功能時(shí),均需先構(gòu)造Worker實(shí)例對(duì)象,其構(gòu)造函數(shù)與API版本相關(guān)。

  1. // 導(dǎo)入模塊
  2. import worker from '@ohos.worker';
  3. // API 9及之后版本使用:
  4. const worker1 = new worker.ThreadWorker(scriptURL);
  5. // API 8及之前版本使用:
  6. const worker1 = new worker.Worker(scriptURL);

構(gòu)造函數(shù)需要傳入Worker的路徑(scriptURL),Worker文件存放位置默認(rèn)路徑為Worker文件所在目錄與pages目錄屬于同級(jí)。

Stage模型

構(gòu)造函數(shù)中的scriptURL示例如下:

  1. // 導(dǎo)入模塊
  2. import worker from '@ohos.worker';
  3. // 寫(xiě)法一
  4. // Stage模型-目錄同級(jí)(entry模塊下,workers目錄與pages目錄同級(jí))
  5. const worker1 = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts', {name:"first worker in Stage model"});
  6. // Stage模型-目錄不同級(jí)(entry模塊下,workers目錄是pages目錄的子目錄)
  7. const worker2 = new worker.ThreadWorker('entry/ets/pages/workers/MyWorker.ts');
  8. // 寫(xiě)法二
  9. // Stage模型-目錄同級(jí)(entry模塊下,workers目錄與pages目錄同級(jí)),假設(shè)bundlename是com.example.workerdemo
  10. const worker3 = new worker.ThreadWorker('@bundle:com.example.workerdemo/entry/ets/workers/worker');
  11. // Stage模型-目錄不同級(jí)(entry模塊下,workers目錄是pages目錄的子目錄),假設(shè)bundlename是com.example.workerdemo
  12. const worker4 = new worker.ThreadWorker('@bundle:com.example.workerdemo/entry/ets/pages/workers/worker');
  • 基于Stage模型工程目錄結(jié)構(gòu),寫(xiě)法一的路徑含義:

    • entry:module.json5文件中module的name屬性對(duì)應(yīng)值。
    • ets:用于存放ets源碼,固定目錄。
    • workers/MyWorker.ts:worker源文件在ets目錄下的路徑。
  • 基于Stage模型工程目錄結(jié)構(gòu),寫(xiě)法二的路徑含義:

    • @bundle:固定標(biāo)簽。
    • bundlename:當(dāng)前應(yīng)用包名。
    • entryname:module.json5文件中module的name屬性對(duì)應(yīng)值。
    • ets:用于存放ets源碼,固定目錄。
    • workerdir/workerfile:worker源文件在ets目錄下的路徑,可不帶文件后綴名。

FA模型

構(gòu)造函數(shù)中的scriptURL示例如下:

  1. // 導(dǎo)入模塊
  2. import worker from '@ohos.worker';
  3. // FA模型-目錄同級(jí)(entry模塊下,workers目錄與pages目錄同級(jí))
  4. const worker1 = new worker.ThreadWorker('workers/worker.js', {name:'first worker in FA model'});
  5. // FA模型-目錄不同級(jí)(entry模塊下,workers目錄與pages目錄的父目錄同級(jí))
  6. const worker2 = new worker.ThreadWorker('../workers/worker.js');

生命周期注意事項(xiàng)

  • Worker的創(chuàng)建和銷(xiāo)毀耗費(fèi)性能,建議開(kāi)發(fā)者合理管理已創(chuàng)建的Worker并重復(fù)使用。Worker空閑時(shí)也會(huì)一直運(yùn)行,因此當(dāng)不需要Worker時(shí),可以調(diào)用terminate()接口或parentPort.close()方法主動(dòng)銷(xiāo)毀Worker。若Worker處于已銷(xiāo)毀或正在銷(xiāo)毀等非運(yùn)行狀態(tài)時(shí),調(diào)用其功能接口,會(huì)拋出相應(yīng)的錯(cuò)誤。

  • Worker存在數(shù)量限制,支持最多同時(shí)存在8個(gè)Worker。

    • 在API version 8及之前的版本,當(dāng)Worker數(shù)量超出限制時(shí),會(huì)拋出“Too many workers, the number of workers exceeds the maximum.”錯(cuò)誤。
    • 從API version 9開(kāi)始,當(dāng)Worker數(shù)量超出限制時(shí),會(huì)拋出“Worker initialization failure, the number of workers exceeds the maximum.”錯(cuò)誤。
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)