1# TaskPool简介 2 3任务池(TaskPool)作用是为应用程序提供一个多线程的运行环境,降低整体资源的消耗、提高系统的整体性能,且您无需关心线程实例的生命周期。具体接口信息及使用方法详情请见[TaskPool](../reference/apis-arkts/js-apis-taskpool.md)。 4 5## TaskPool运作机制 6 7TaskPool运作机制示意图 8 9 10 11TaskPool支持开发者在宿主线程封装任务抛给任务队列,系统选择合适的工作线程,进行任务的分发及执行,再将结果返回给宿主线程。接口直观易用,支持任务的执行、取消,以及指定优先级的能力,同时通过系统统一线程管理,结合动态调度及负载均衡算法,可以节约系统资源。系统默认会启动一个任务工作线程,当任务较多时会扩容,工作线程数量上限跟当前设备的物理核数相关,具体数量内部管理,保证最优的调度及执行效率,长时间没有任务分发时会缩容,减少工作线程数量。 12 13## TaskPool注意事项 14 15- 实现任务的函数需要使用[@Concurrent装饰器](#concurrent装饰器)标注,且仅支持在.ets文件中使用。 16 17- 从API version 11开始,跨并发实例传递带方法的实例对象时,该类必须使用装饰器[@Sendable装饰器](arkts-sendable.md#sendable装饰器)标注,且仅支持在.ets文件中使用。 18 19- 任务函数在TaskPool工作线程的执行耗时不能超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时),否则会被强制退出。 20 21- 实现任务的函数入参需满足序列化支持的类型,详情请参见[线程间通信对象](interthread-communication-overview.md)。 22 23- ArrayBuffer参数在TaskPool中默认转移,需要设置转移列表的话可通过接口[setTransferList()](../reference/apis-arkts/js-apis-taskpool.md#settransferlist10)设置。 24 25- 由于不同线程中上下文对象是不同的,因此TaskPool工作线程只能使用线程安全的库,例如UI相关的非线程安全库不能使用。 26 27- 序列化传输的数据量大小限制为16MB。 28 29- [Priority](../reference/apis-arkts/js-apis-taskpool.md#priority)的IDLE优先级是用来标记需要在后台运行的耗时任务(例如数据同步、备份),它的优先级别是最低的。这种优先级标记的任务只会在所有线程都空闲的情况下触发执行,并且只会占用一个线程来执行。 30 31- Promise不支持跨线程传递,如果TaskPool返回pending或rejected状态的Promise,会返回失败;对于fulfilled状态的Promise,TaskPool会解析返回的结果,如果结果可以跨线程传递,则返回成功。 32 33- 不支持在TaskPool工作线程中使用[AppStorage](../quick-start/arkts-appstorage.md)。 34 35## \@Concurrent装饰器 36 37在使用[TaskPool](../reference/apis-arkts/js-apis-taskpool.md)时,执行的并发函数需要使用该装饰器修饰,否则无法通过相关校验。 38 39> **说明:** 40> 41> 从API version 9开始,支持使用\@Concurrent装饰器声明并校验并发函数。 42 43### 装饰器说明 44 45| \@Concurrent并发装饰器 | 说明 | 46| -------- | -------- | 47| 装饰器参数 | 无。 | 48| 使用场景 | 仅支持在Stage模型的工程中使用。仅支持在.ets文件中使用。 | 49| 装饰的函数类型 | 允许标注async函数或普通函数。禁止标注generator、箭头函数、类方法。不支持类成员函数或者匿名函数。 | 50| 装饰的函数内的变量类型 | 允许使用local变量、入参和通过import引入的变量。禁止使用闭包变量。 | 51| 装饰的函数内的返回值类型 | 支持的类型请查[线程间通信对象](interthread-communication-overview.md)。 | 52 53> **说明:** 54> 55> 由于\@Concurrent标记的函数不能访问闭包,因此\@Concurrent标记的函数内部不能调用当前文件的其他函数,例如: 56> 57> ```ts 58> function bar() { 59> } 60> 61> @Concurrent 62> function foo() { 63> bar(); // 违反闭包原则,报错 64> } 65> ``` 66 67### 装饰器使用示例 68 69#### 并发函数一般使用 70 71并发函数为一个计算两数之和的普通函数,taskpool执行该函数并返回结果。 72 73示例: 74 75```ts 76import { taskpool } from '@kit.ArkTS'; 77 78@Concurrent 79function add(num1: number, num2: number): number { 80 return num1 + num2; 81} 82 83async function ConcurrentFunc(): Promise<void> { 84 try { 85 let task: taskpool.Task = new taskpool.Task(add, 1, 2); 86 console.info("taskpool res is: " + await taskpool.execute(task)); 87 } catch (e) { 88 console.error("taskpool execute error is: " + e); 89 } 90} 91 92@Entry 93@Component 94struct Index { 95 @State message: string = 'Hello World' 96 97 build() { 98 Row() { 99 Column() { 100 Text(this.message) 101 .fontSize(50) 102 .fontWeight(FontWeight.Bold) 103 .onClick(() => { 104 ConcurrentFunc(); 105 }) 106 } 107 .width('100%') 108 } 109 .height('100%') 110 } 111} 112``` 113 114#### 并发函数返回Promise 115 116并发函数中返回Promise的表现需关注,如下例所示,其中testPromise、testPromise1等并发同步函数会处理该Promise并返回结果。 117 118示例: 119 120```ts 121import { taskpool } from '@kit.ArkTS'; 122 123@Concurrent 124function testPromise(args1: number, args2: number): Promise<number> { 125 return new Promise<number>((testFuncA, testFuncB)=>{ 126 testFuncA(args1 + args2); 127 }); 128} 129 130@Concurrent 131async function testPromise1(args1: number, args2: number): Promise<number> { 132 return new Promise<number>((testFuncA, testFuncB)=>{ 133 testFuncA(args1 + args2); 134 }); 135} 136 137@Concurrent 138async function testPromise2(args1: number, args2: number): Promise<number> { 139 return await new Promise<number>((testFuncA, testFuncB)=>{ 140 testFuncA(args1 + args2); 141 }); 142} 143 144@Concurrent 145function testPromise3() { 146 return Promise.resolve(1); 147} 148 149@Concurrent 150async function testPromise4(): Promise<number> { 151 return 1; 152} 153 154@Concurrent 155async function testPromise5(): Promise<string> { 156 return await new Promise((resolve) => { 157 setTimeout(()=>{ 158 resolve("Promise setTimeout after resolve"); 159 }, 1000) 160 }); 161} 162 163async function testConcurrentFunc() { 164 let task1: taskpool.Task = new taskpool.Task(testPromise, 1, 2); 165 let task2: taskpool.Task = new taskpool.Task(testPromise1, 1, 2); 166 let task3: taskpool.Task = new taskpool.Task(testPromise2, 1, 2); 167 let task4: taskpool.Task = new taskpool.Task(testPromise3); 168 let task5: taskpool.Task = new taskpool.Task(testPromise4); 169 let task6: taskpool.Task = new taskpool.Task(testPromise5); 170 171 taskpool.execute(task1).then((d:object)=>{ 172 console.info("task1 res is: " + d); 173 }).catch((e:object)=>{ 174 console.info("task1 catch e: " + e); 175 }) 176 taskpool.execute(task2).then((d:object)=>{ 177 console.info("task2 res is: " + d); 178 }).catch((e:object)=>{ 179 console.info("task2 catch e: " + e); 180 }) 181 taskpool.execute(task3).then((d:object)=>{ 182 console.info("task3 res is: " + d); 183 }).catch((e:object)=>{ 184 console.info("task3 catch e: " + e); 185 }) 186 taskpool.execute(task4).then((d:object)=>{ 187 console.info("task4 res is: " + d); 188 }).catch((e:object)=>{ 189 console.info("task4 catch e: " + e); 190 }) 191 taskpool.execute(task5).then((d:object)=>{ 192 console.info("task5 res is: " + d); 193 }).catch((e:object)=>{ 194 console.info("task5 catch e: " + e); 195 }) 196 taskpool.execute(task6).then((d:object)=>{ 197 console.info("task6 res is: " + d); 198 }).catch((e:object)=>{ 199 console.info("task6 catch e: " + e); 200 }) 201} 202 203@Entry 204@Component 205struct Index { 206 @State message: string = 'Hello World'; 207 208 build() { 209 Row() { 210 Column() { 211 Button(this.message) 212 .fontSize(50) 213 .fontWeight(FontWeight.Bold) 214 .onClick(() => { 215 testConcurrentFunc(); 216 }) 217 } 218 .width('100%') 219 } 220 .height('100%') 221 } 222} 223``` 224 225#### 并发函数中使用自定义类或函数 226 227并发函数中使用自定义类或函数时需定义在不同文件,否则会被认为是闭包,如下例所示。 228 229示例: 230 231```ts 232// Index.ets 233import { taskpool } from '@kit.ArkTS'; 234import { BusinessError } from '@kit.BasicServicesKit'; 235import { testAdd, MyTestA, MyTestB } from './Test'; 236 237function add(arg: number) { 238 return ++arg; 239} 240 241class TestA { 242 constructor(name: string) { 243 this.name = name; 244 } 245 name: string = 'ClassA'; 246} 247 248class TestB { 249 static nameStr: string = 'ClassB'; 250} 251 252@Concurrent 253function TestFunc() { 254 // case1:在并发函数中直接调用同文件内定义的类或函数 255 256 // 直接调用同文件定义的函数add(),add飘红报错:Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck> 257 // add(1); 258 // 直接使用同文件定义的TestA构造,TestA飘红报错:Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck> 259 // let a = new TestA("aaa"); 260 // 直接访问同文件定义的TestB的成员nameStr,TestB飘红报错:Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck> 261 // console.info("TestB name is: " + TestB.nameStr); 262 263 // case2:在并发函数中调用定义在Test.ets文件并导入当前文件的类或函数 264 265 // 输出结果:res1 is: 2 266 console.info("res1 is: " + testAdd(1)); 267 let tmpStr = new MyTestA("TEST A"); 268 // 输出结果:res2 is: TEST A 269 console.info("res2 is: " + tmpStr.name); 270 // 输出结果:res3 is: MyTestB 271 console.info("res3 is: " + MyTestB.nameStr); 272} 273 274 275@Entry 276@Component 277struct Index { 278 @State message: string = 'Hello World'; 279 280 build() { 281 RelativeContainer() { 282 Text(this.message) 283 .id('HelloWorld') 284 .fontSize(50) 285 .fontWeight(FontWeight.Bold) 286 .alignRules({ 287 center: { anchor: '__container__', align: VerticalAlign.Center }, 288 middle: { anchor: '__container__', align: HorizontalAlign.Center } 289 }) 290 .onClick(() => { 291 let task = new taskpool.Task(TestFunc); 292 taskpool.execute(task).then(() => { 293 console.info("taskpool: execute task success!"); 294 }).catch((e:BusinessError) => { 295 console.error(`taskpool: execute: Code: ${e.code}, message: ${e.message}`); 296 }) 297 }) 298 } 299 .height('100%') 300 .width('100%') 301 } 302} 303``` 304 305```ts 306// Test.ets 307export function testAdd(arg: number) { 308 return ++arg; 309} 310 311@Sendable 312export class MyTestA { 313 constructor(name: string) { 314 this.name = name; 315 } 316 name: string = 'MyTestA'; 317} 318 319export class MyTestB { 320 static nameStr:string = 'MyTestB'; 321} 322``` 323 324#### 并发异步函数中使用Promise 325 326并发异步函数中如果使用Promise,建议搭配await使用捕获Promise中可能发生的异常。推荐使用示例如下。 327 328示例: 329 330```ts 331import { taskpool } from '@kit.ArkTS' 332 333@Concurrent 334async function testPromiseError() { 335 await new Promise<number>((resolve, reject) => { 336 resolve(1); 337 }).then(()=>{ 338 throw new Error("testPromise Error"); 339 }) 340} 341 342@Concurrent 343async function testPromiseError1() { 344 await new Promise<string>((resolve, reject) => { 345 reject("testPromiseError1 Error msg"); 346 }) 347} 348 349@Concurrent 350function testPromiseError2() { 351 return new Promise<string>((resolve, reject) => { 352 reject("testPromiseError2 Error msg"); 353 }) 354} 355 356async function testConcurrentFunc() { 357 let task1: taskpool.Task = new taskpool.Task(testPromiseError); 358 let task2: taskpool.Task = new taskpool.Task(testPromiseError1); 359 let task3: taskpool.Task = new taskpool.Task(testPromiseError2); 360 361 taskpool.execute(task1).then((d:object)=>{ 362 console.info("task1 res is: " + d); 363 }).catch((e:object)=>{ 364 console.info("task1 catch e: " + e); 365 }) 366 taskpool.execute(task2).then((d:object)=>{ 367 console.info("task2 res is: " + d); 368 }).catch((e:object)=>{ 369 console.info("task2 catch e: " + e); 370 }) 371 taskpool.execute(task3).then((d:object)=>{ 372 console.info("task3 res is: " + d); 373 }).catch((e:object)=>{ 374 console.info("task3 catch e: " + e); 375 }) 376} 377 378@Entry 379@Component 380struct Index { 381 @State message: string = 'Hello World'; 382 383 build() { 384 Row() { 385 Column() { 386 Button(this.message) 387 .fontSize(50) 388 .fontWeight(FontWeight.Bold) 389 .onClick(() => { 390 testConcurrentFunc(); 391 }) 392 } 393 .width('100%') 394 } 395 .height('100%') 396 } 397} 398``` 399