1# TaskPool Introduction
2
3TaskPool provides a multithreaded environment for applications. It helps reduce 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
7TaskPool operating mechanism
8
9![image_0000001964858368](figures/image_0000001964858368.png)
10
11With TaskPool, you can encapsulate tasks in the main thread and throw the tasks to the task queue. The system selects proper worker threads to distribute and execute the tasks, and then returns the result to the main 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 a long period of time, the system reduces the number of worker threads.
12
13## Precautions for TaskPool
14
15- A task function must be decorated with [\@Concurrent](#concurrent-decorator) and can be used only in .ets files.
16
17- Since API version 11, when an instance object with a method is passed across concurrent instances, the class must be annotated with the decorator [@Sendable](arkts-sendable.md#sendable) and can be used only in .ets files.
18
19- A task function in the TaskPool worker thread must finish the execution within 3 minutes (excluding the time used for Promise or async/await asynchronous call, for example, the duration of I/O tasks such as network download and file read/write). Otherwise, it forcibly exits.
20
21- The input parameters of the function for implementing the task must meet the types supported by serialization. For details, see [Inter-Thread Communication Object](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, rather than UI-related non-thread-safe libraries.
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 (such as data synchronization and backup) that need to run in the background Tasks marked with **IDLE** are executed only when all threads are idle and occupy only one thread for execution.
30
31- Promises cannot be transferred across threads. If the TaskPool returns a promise in the pending or rejected state, a failure message is returned. For a promise in the fulfilled state, the 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 the TaskPool worker thread.
34
35## \@Concurrent Decorator
36
37To pass function verification, the 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| The decorator can be used only in projects of the stage model. It can be used only in .ets files.|
49| Decorated function types| This decorator can be used for asynchronous functions and common functions. It cannot be used for generators, arrow functions, or methods. It does not support class member functions or anonymous functions.|
50| Variable types in decorated functions| Local variables, input parameters, and variables imported through **import** are supported. Closure variables are not allowed.|
51| Return value types in decorated functions| For details about the supported types, see [Inter-Thread Communication Object](interthread-communication-overview.md).|
52
53> **Note**
54>
55> Functions marked by \@Concurrent cannot access closures. Therefore, functions marked by \@Concurrent cannot call other functions of the current file. For example:
56>
57> ```ts
58> function bar() {
59> }
60>
61> @Concurrent
62> function foo() {
63> bar (); // The closure principle is violated. An error is reported.
64> }
65> ```
66
67### Decorator Example
68
69#### Commonly used by concurrent functions
70
71A concurrent function is a common function that calculates the sum of two numbers. The taskpool executes the function 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#### Promise returned by concurrent functions
115
116Pay attention to the performance of returning Promise in the concurrent function. The concurrent synchronous function processes and returns Promise with the result.
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 a User-Defined Class or Function in a Concurrent Function
226
227User-defined classes or functions used in concurrent functions must be defined in different 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 in a concurrent function.
255
256  // Directly call the add () function defined in the same file. The error message "Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>" is displayed in red.
257  // add(1);
258  // Use the TestA defined in the same file. The error message "Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>" is displayed.
259  // let a = new TestA("aaa");
260  // Directly access the nameStr member of TestB defined in the same file. The error message "Only imported variables and local variables can be used in @Concurrent decorated functions. <ArkTSCheck>" is displayed in red.
261  // console.info("TestB name is: " + TestB.nameStr);
262
263  // Case 2: In the concurrent function, call the class or function defined in the Test.ets file and import the current file.
264
265  // Output result: res1 is: 2
266  console.info("res1 is: " + testAdd(1));
267  let tmpStr = new MyTestA("TEST A");
268  // Output result: 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 Promise in a Concurrent Asynchronous Function
325
326If Promise is used in the concurrent asynchronous function, you are advised to use await to capture exceptions that may occur in Promise. A recommended example is provided below.
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