• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# TaskPool
2
3TaskPool is designed to provide a multithreaded runtime environment for applications. It helps reduce overall resource consumption and improve system performance. It also frees you from caring about the lifecycle of thread instances. For details about the APIs and their usage, see [TaskPool](../reference/apis-arkts/js-apis-taskpool.md).
4
5## TaskPool Operating Mechanism
6
7The figure below illustrates the operating mechanism of TaskPool.
8
9![image_0000001964858368](figures/image_0000001964858368.png)
10
11With TaskPool, you can encapsulate tasks in the host thread and submit the tasks to the task queue. The system selects appropriate worker threads to distribute and execute the tasks, and then returns the result to the host thread. TaskPool provides APIs to execute and cancel tasks, and set the task priority. It minimizes system resource usage through unified thread management, dynamic scheduling, and load balancing. By default, the system starts a worker thread and increases the thread quantity as the number of tasks increases. The maximum number of worker threads that can be created depends on the number of physical cores of the device. The actual number is managed internally to ensure optimal scheduling and execution efficiency. If no task is distributed for an extended period, the system reduces the number of worker threads.
12
13## Precautions for TaskPool
14
15- Functions implementing tasks must be decorated with [\@Concurrent](#concurrent-decorator) and are supported only in .ets files.
16
17- Starting from API version 11, when passing instances with methods across concurrent instances, the class must be decorated with [@Sendable](arkts-sendable.md#sendable) and are supported only in .ets files.
18
19- A task function must finish the execution in a TaskPool worker thread within 3 minutes (excluding the time used for Promise or async/await asynchronous call, such as the duration of I/O tasks like network download and file read/write operation). Otherwise, it is forcibly terminated.
20
21- Parameters of functions implementing tasks must be of types supported by serialization. For details, see [Inter-Thread Communication](interthread-communication-overview.md).
22
23- Parameters of the ArrayBuffer type are transferred in TaskPool by default. You can set the transfer list by calling [setTransferList()](../reference/apis-arkts/js-apis-taskpool.md#settransferlist10).
24
25- The context objects in different threads are different. Therefore, TaskPool worker threads can use only thread-safe libraries. For example, non-thread-safe UI-related libraries cannot be used.
26
27- A maximum of 16 MB data can be serialized.
28
29- Among all the values of [Priority](../reference/apis-arkts/js-apis-taskpool.md#priority), **IDLE** is used to mark time-consuming tasks that need to run in the background (such as data synchronization and backup), and it has the lowest priority. Tasks marked with this priority are executed only when all threads are idle and occupy only one thread for execution.
30
31- Promises cannot be transferred across threads. If TaskPool returns a Promise in the pending or rejected state, a failure message is returned. For a Promise in the fulfilled state, TaskPool parses the returned result. If the result can be transferred across threads, a success message is returned.
32
33- [AppStorage](../quick-start/arkts-appstorage.md) cannot be used in TaskPool worker threads.
34
35## \@Concurrent Decorator
36
37To pass function verification, concurrent functions executed in a [TaskPool](../reference/apis-arkts/js-apis-taskpool.md) must be decorated using \@Concurrent.
38
39> **NOTE**
40>
41> Since API version 9, the @Concurrent decorator can be used to declare and verify concurrent functions.
42
43### Decorator Description
44
45| \@Concurrent Decorator| Description|
46| -------- | -------- |
47| Decorator parameters| None.|
48| Use scenario| Used only in projects of the stage model and only in .ets files.|
49| Decorated function types| Used for async functions or regular functions. It cannot be used for generators, arrow functions, or class methods. It does not support class member functions or anonymous functions.|
50| Variable types in decorated functions| Local variables, parameters, and variables imported via **import** are allowed. Closure variables are prohibited.|
51| Return value types in decorated functions| Supported types are listed in [Inter-Thread Communication](interthread-communication-overview.md). |
52
53> **NOTE**
54>
55> Functions decorated with \@Concurrent cannot access closures. Therefore, they cannot call other functions within the same file. The following provides an example.
56>
57> ```ts
58> function bar() {
59> }
60>
61> @Concurrent
62> function foo() {
63> bar(); // This violates the closure principle. An error is reported.
64> }
65> ```
66
67### Decorator Usage Examples
68
69#### General Use of Concurrent Functions
70
71A concurrent function that calculates the sum of two numbers is executed by TaskPool and returns the result.
72
73Example:
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#### Concurrent Functions Returning Promises
115
116Pay attention to the behavior of returning Promises in concurrent functions. In the following example, concurrent functions like **testPromise** and **testPromise1** handle these Promises and return results.
117
118Example:
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#### Using Custom Classes or Functions in Concurrent Functions
226
227Custom classes or functions used in concurrent functions must be defined in separate files. Otherwise, they will be considered as closures, as shown in the following example.
228
229Example:
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  // Case 1: Directly call a class or function defined in the same file within a concurrent function.
255
256  // Directly call the add() function defined in the same file. The following error message is displayed: "Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>"
257  // add(1);
258  // Directly use the TestA constructor defined in the same file. The following error message is displayed: "Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>"
259  // let a = new TestA("aaa");
260  // Directly access the nameStr member of TestB defined in the same file. The following error message is displayed: "Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>"
261  // console.info("TestB name is: " + TestB.nameStr);
262
263  // Case 2: In the concurrent function, call classes or functions defined in the Test.ets file and imported into the current file.
264
265  // Output: res1 is: 2
266  console.info("res1 is: " + testAdd(1));
267  let tmpStr = new MyTestA("TEST A");
268  // Output: res2 is: TEST A
269  console.info("res2 is: " + tmpStr.name);
270  // Output: 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#### Using Promises in Concurrent Asynchronous Functions
325
326If Promise is used in concurrent asynchronous functions, you are advised to use await to enable TaskPool to capture any exceptions that may occur within the Promise. The recommended usage is shown in the following example.
327
328Example:
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