自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

多線程任務(wù)開發(fā)范例-TaskPool

開發(fā) 前端
任務(wù)池(Taskpool)為應(yīng)用程序提供一個(gè)多線程的運(yùn)行環(huán)境,可以使用任務(wù)池API創(chuàng)建后臺(tái)任務(wù)(Task),并對(duì)所創(chuàng)建的任務(wù)進(jìn)行如任務(wù)執(zhí)行、任務(wù)取消的操作。

想了解更多關(guān)于開源的內(nèi)容,請?jiān)L問:

51CTO 開源基礎(chǔ)軟件社區(qū)

https://ost.51cto.com

概念介紹

任務(wù)池(taskpool)為應(yīng)用程序提供一個(gè)多線程的運(yùn)行環(huán)境,可以使用任務(wù)池API創(chuàng)建后臺(tái)任務(wù)(Task),并對(duì)所創(chuàng)建的任務(wù)進(jìn)行如任務(wù)執(zhí)行、任務(wù)取消的操作。使用任務(wù)池,無需關(guān)心線程實(shí)例的生命周期,提升開發(fā)體驗(yàn),還能降低整體資源的消耗、提高系統(tǒng)的整體性能。

API接口

任務(wù)池模塊提供的功能非?;A(chǔ),只支持任務(wù)構(gòu)造,任務(wù)執(zhí)行,任務(wù)取消等3類接口。關(guān)于任務(wù)池(taskpool)API能力詳細(xì)信息,請參考@ohos.taskpool。本節(jié)只進(jìn)行關(guān)鍵接口解讀。

Task構(gòu)造函數(shù)

使用線程池運(yùn)行后臺(tái)任務(wù)前,可以先構(gòu)造一個(gè)Task實(shí)例。Task構(gòu)造函數(shù)如下:

constructor(func: Function, …args: unknown[])

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

參數(shù)名

類型

必填

說明

func

Function

任務(wù)執(zhí)行需要傳入函數(shù),支持的函數(shù)返回值類型請查序列化支持類型。

args

unknown[]

任務(wù)執(zhí)行傳入函數(shù)的參數(shù),支持的參數(shù)類型請查序列化支持類型。默認(rèn)值為undefined。

我們來看一個(gè)構(gòu)造的示例。

@Concurrent
function printArgs(args) {
    console.log("printArgs: " + args);
    return args;
}

let task = new taskpool.Task(printArgs, "this is my first Task");

注意:上述實(shí)例代碼是官方API提供的,實(shí)際上并不可用,使用裝飾器@Concurrent會(huì)報(bào)錯(cuò)。實(shí)際上使用的是如下代碼:

function concurrentTask(durationMs: number) {
  "use concurrent"
  console.info("[concurrentTask] task start, the args is " + durationMs)
  setTimeout(() => {
    console.info("[concurrentTask] task end ")
  }, durationMs)
  console.info("[concurrentTask] task return")
  return '[concurrentTask] returned'
}

function createTask() {
  let task = new taskPool.Task(concurrentTask, 10 * 1000)
  console.info("[createTask] created successfully")
  return task
}

執(zhí)行異步函數(shù)

將待執(zhí)行的函數(shù)放入taskpool內(nèi)部任務(wù)隊(duì)列等待,等待分發(fā)到工作線程執(zhí)行。此種方式執(zhí)行的情況下,沒有創(chuàng)建任務(wù),所以不可取消任務(wù)。后文將介紹的taskpool.cancel函數(shù)需要傳入taskpool.Task參數(shù)。
接口定義如下,其中的參數(shù)不再解釋,和Task構(gòu)造函數(shù)的參數(shù)一樣。

execute(func: Function, …args: unknown[]): Promise<unknown>

示例代碼如下:

@Concurrent
function printArgs(args) {
    console.log("printArgs: " + args);
    return args;
}

async function taskpoolExecute() {
  let value = await taskpool.execute(printArgs, 100);
  console.log("taskpool result: " + value);
}
...
taskpoolExecute();

執(zhí)行Task任務(wù)

將創(chuàng)建好的任務(wù)放入taskpool任務(wù)池里等待,等待分發(fā)到工作線程執(zhí)行。當(dāng)前執(zhí)行模式可嘗試調(diào)用cancel進(jìn)行任務(wù)取消。接口定義如下:

execute(task: Task, priority?: Priority): Promise<unknown>

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

參數(shù)名

類型

必填

說明

task

Task

需要在任務(wù)池中執(zhí)行的任務(wù)。

priority

Priority

等待執(zhí)行的任務(wù)的優(yōu)先級(jí)(暫未支持)。

示例代碼如下:

@Concurrent
function printArgs(args) {
    console.log("printArgs: " + args);
    return args;
}

async function taskpoolExecute() {
  let task = new taskpool.Task(printArgs, 100);
  let value = await taskpool.execute(task);
  console.log("taskpool result: " + value);
}

taskpoolExecute();

取消Task任務(wù)

取消任務(wù)池中的任務(wù)。在Task構(gòu)造實(shí)例后直接調(diào)用cancal接口會(huì)找不到要取消的任務(wù),需要調(diào)用execute接口后,才會(huì)放入任務(wù)池,調(diào)用cancel接口才有意義。

接口定義如下:

cancel(task: Task): void

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

參數(shù)名

類型

必填

說明

task

Task

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

示例代碼如下:

@Concurrent
function printArgs(args) {
    console.log("printArgs: " + args);
    return args;
}

async function taskpoolCancel() {
  let task = new taskpool.Task(printArgs, 100);
  taskpool.execute(task);
  try {
    taskpool.cancel(task);
  } catch (e) {
    console.log("taskpool.cancel occur error:" + e);
  }
}

taskpoolCancel();

實(shí)現(xiàn)場景

我們主要為了體驗(yàn)線程池的使用,實(shí)現(xiàn)任務(wù)創(chuàng)建、任務(wù)執(zhí)行和任務(wù)取消的功能。為了簡化,相關(guān)輸出使用console控制輸出即可。

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

簡化界面實(shí)現(xiàn),只需要簡單地包含一個(gè)text和三個(gè)button。text用于展示接口調(diào)用信息,不同的button按鈕被點(diǎn)擊后觸發(fā)調(diào)用不同的接口。通過設(shè)置日志查看操作執(zhí)行情況。

開發(fā)步驟

UI界面實(shí)現(xiàn)

代碼非常簡單,使用DevEco Studio創(chuàng)建一個(gè)Empty Ability空工程后,加3個(gè)按鈕就行。

“Create Task"按鈕會(huì)創(chuàng)建一個(gè)任務(wù)。創(chuàng)建的Task實(shí)例會(huì)賦值給組件的變量,創(chuàng)建任務(wù)的代碼如下?,F(xiàn)在存在一個(gè)問題需要確認(rèn),@concurrent裝飾器不知道如何使用,
當(dāng)前使用的"use concurrent”。需要確認(rèn)官方文檔是否存在問題。

function concurrentTask(durationMs: number) {
  "use concurrent"
  console.info("[concurrentTask] task start, the args is " + durationMs)
  setTimeout(() => {
    console.info("[concurrentTask] task end ")
  }, durationMs)
  console.info("[concurrentTask] task return")
  return '[concurrentTask] returned'
}

function createTask() {
  let task = new taskPool.Task(concurrentTask, 10 * 1000)
  console.info("[createTask] created successfully")
  return task
}

"Execute Task"按鈕會(huì)執(zhí)行一個(gè)任務(wù)。組件的變量持有任務(wù),該按鈕可以持續(xù)點(diǎn)擊,反復(fù)執(zhí)行任務(wù)。

"Cancel Task"按鈕會(huì)取消一個(gè)任務(wù)。如果認(rèn)為沒有調(diào)用execute接口,不在線程池里,取消會(huì)阿伯錯(cuò);如果任務(wù)正在執(zhí)行中,再去取消也會(huì)報(bào)錯(cuò)。實(shí)際上運(yùn)行,沒有得到想要的效果,需要進(jìn)一步確認(rèn)。

UI代碼

entry\src\main\ets\pages\Index.ets文件片段如下:

task: taskPool.Task = null
   ...
  Column() {
	Text(this.message)
	  .fontSize(20)
	  .fontWeight(FontWeight.Bold)
	Blank()
	Row() {
	  Button("Create Task").onClick(() => {
		this.task = createTask()
		this.message = "Task Created"
	  })
	  Button("Execute Task").onClick(() => {
		executeTask(this.task)
		this.message = "Task Executed"
	  })
	  Button("Cancel Task").onClick(() => {
		cancelTask(this.task)
		this.message = "Task Cancel involved"
	  })
	}

  }

執(zhí)行任務(wù)代碼實(shí)現(xiàn)

我們再執(zhí)行任務(wù)代碼如何實(shí)現(xiàn)。

我們從上文知道,taskPool.execute接口有兩種方式,可以傳入異步函數(shù)和參數(shù),也可以傳入task實(shí)例和優(yōu)先級(jí)參數(shù)。

此處,我們使用第二種方法,傳入task實(shí)例和優(yōu)先級(jí)參數(shù)。任務(wù)池模塊尚未支持優(yōu)先級(jí),該參數(shù)也可以省略。

執(zhí)行任務(wù)代碼片段如下:

function executeTask(task: taskPool.Task) {
  console.info("[executeTask] executing")
  try {
    taskPool.execute(task, taskPool.Priority.HIGH).then(() => {
      console.info("[executeTask] executed successfully")
    })
  } catch (e) {
    console.error("[executeTask] execute failed, " + e.toString())
  }
}

取消任務(wù)代碼實(shí)現(xiàn)

我們再看下取消任務(wù)的代碼如何實(shí)現(xiàn)。

如果沒有通過調(diào)用execute接口,沒有放入任務(wù)池的task,執(zhí)行cancel函數(shù)時(shí),會(huì)報(bào)異常,畢竟在線程池是不存在的。

然后模擬一個(gè)延時(shí)操作,再去調(diào)用cancel函數(shù)。

期望可以正常取消任務(wù),實(shí)際上,任務(wù)沒有被取消,也沒有報(bào)異常。這里就很奇怪,需要繼續(xù)調(diào)查原因。

取消任務(wù)代碼片段:

function cancelTask(task: taskPool.Task) {
  console.info("[cancelTask] canceling ")
  try {
    taskPool.execute(task, taskPool.Priority.HIGH)
    let start = new Date().getTime()
    // 延時(shí)1s,確保任務(wù)已執(zhí)行
    while (new Date().getTime() - start < 1000) {
      continue
    }
    taskPool.cancel(task)
  } catch (e) {
    console.error("[cancelTask] cancel failed" + e.toString())
  }
}

運(yùn)行測試效果

代碼編寫完畢,可以測試運(yùn)行查看效果。推薦在模塊級(jí)配置文件entry\build-profile.json5中,修改運(yùn)行時(shí)為"HarmonyOS",這樣就可以在DevEco Studio中使用Simulator模擬器進(jìn)行運(yùn)行測試,手頭沒有設(shè)備也可以輕松體驗(yàn)OpenHarmony應(yīng)用開發(fā)。分別點(diǎn)擊按鈕,日志輸出如下:

07-30 22:28:28.357 4214-7232/com.example.taskpooldemo I 0FEFE/JsApp: [createTask] created successfully
07-30 22:28:30.576 4214-7232/com.example.taskpooldemo I 0FEFE/JsApp: [executeTask] executing
07-30 22:28:30.576 4214-7256/com.example.taskpooldemo I 0FEFE/JsApp: [concurrentTask] task start, the args is 10000
07-30 22:28:30.576 4214-7256/com.example.taskpooldemo I 0FEFE/JsApp: [concurrentTask] task return
07-30 22:28:30.577 4214-7232/com.example.taskpooldemo I 0FEFE/JsApp: [executeTask] executed successfully
07-30 22:28:37.602 4214-7232/com.example.taskpooldemo I 0FEFE/JsApp: [cancelTask] canceling
07-30 22:28:37.608 4214-7256/com.example.taskpooldemo I 0FEFE/JsApp: [concurrentTask] task start, the args is 10000
07-30 22:28:37.609 4214-7256/com.example.taskpooldemo I 0FEFE/JsApp: [concurrentTask] task return
07-30 22:28:38.607 4214-7232/com.example.taskpooldemo E 0FEFE/JsApp: [cancelTask] cancel failedBusinessError: The task does not exist when it is canceled, taskpool:: can not find the task
07-30 22:28:40.580 4214-7256/com.example.taskpooldemo I 0FEFE/JsApp: [concurrentTask] task end
07-30 22:28:47.608 4214-7256/com.example.taskpooldemo I 0FEFE/JsApp: [concurrentTask] task end

注意事項(xiàng)

理論上,您可以使用任務(wù)池API創(chuàng)建數(shù)量不受限制的任務(wù)。當(dāng)同一時(shí)間待執(zhí)行的任務(wù)數(shù)量大于任務(wù)池工作線程數(shù)量,任務(wù)池會(huì)根據(jù)負(fù)載均衡機(jī)制進(jìn)行擴(kuò)容,增加工作線程數(shù)量,減少整體等待時(shí)長。同樣,當(dāng)執(zhí)行的任務(wù)數(shù)量減少,工作線程數(shù)量大于執(zhí)行任務(wù)數(shù)量,部分工作線程處于空閑狀態(tài),任務(wù)池會(huì)根據(jù)負(fù)載均衡機(jī)制進(jìn)行縮容,減少工作線程數(shù)量。遺憾的是,負(fù)載均衡機(jī)制暫未支持。

創(chuàng)建的同一優(yōu)先級(jí)任務(wù)的執(zhí)行順序可以由您決定,任務(wù)真實(shí)執(zhí)行的順序與您調(diào)用任務(wù)池API提供的任務(wù)執(zhí)行接口順序一致。任務(wù)默認(rèn)優(yōu)先級(jí)是taskPool.Priority.MEDIUM。遺憾的是,任務(wù)優(yōu)先級(jí)機(jī)制暫未支持,可以忽略。

@concurrent裝飾器如何使用,需要繼續(xù)確認(rèn)。另外,官方文檔中提到:僅支持在Stage模型且module的compileMode為esmodule的project中使用taskpool api。compileMode設(shè)置為什么看起來并不影響什么,需要進(jìn)一步確認(rèn)。

最后,任務(wù)池模塊現(xiàn)在屬于基礎(chǔ)版本,接口支持只支持簡單的任務(wù)執(zhí)行和取消功能,查詢運(yùn)行狀態(tài)等接口也不支持。任務(wù)一旦執(zhí)行,不支持取消。不建議您在任務(wù)中執(zhí)行阻塞操作,特別是無限期阻塞操作,長時(shí)間的阻塞操作占據(jù)工作線程,可能會(huì)阻塞其他任務(wù)調(diào)度,影響您的應(yīng)用性能。

想了解更多關(guān)于開源的內(nèi)容,請?jiān)L問:

51CTO 開源基礎(chǔ)軟件社區(qū)

https://ost.51cto.com

責(zé)任編輯:jianghua 來源: 51CTO 開源基礎(chǔ)軟件社區(qū)
相關(guān)推薦

2023-08-01 16:35:48

鴻蒙ArkUI應(yīng)用開發(fā)

2010-02-04 10:19:39

C++多線程

2021-09-09 07:16:00

C#多線程開發(fā)

2011-05-31 13:29:40

Android 多線程

2015-11-18 18:56:36

Java多線程處理

2015-07-22 09:39:38

IOS多線程同步

2015-07-22 09:51:51

iOS開發(fā)線程

2009-07-17 17:29:13

多任務(wù)多線程

2009-08-13 09:07:36

Java多線程

2019-09-26 10:19:27

設(shè)計(jì)電腦Java

2022-04-14 11:44:25

LiteOS線程鴻蒙

2022-10-11 08:00:47

多線程開發(fā)技巧

2010-03-18 10:36:23

Java語言規(guī)范

2011-08-12 10:09:23

iPhone開發(fā)多線程

2015-07-08 09:56:25

Notificatio多線程

2011-08-18 17:07:23

IOS開發(fā)多線程NSInvocatio

2009-09-22 17:21:24

線程局部變量

2009-03-12 10:52:43

Java線程多線程

2011-08-08 13:50:29

iPhone開發(fā) NSOperatio 多線程

2009-04-24 09:14:20

.NET多線程鎖機(jī)制
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)