• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Synchronous Task Development (TaskPool and Worker)
2
3
4Synchronous tasks involve coordinating execution across multiple threads to ensure that tasks run in a specific order and adhere to certain rules, such as using locks to prevent data races.
5
6
7To implement synchronous tasks, you must consider the collaboration and synchronization between multiple threads and ensure data integrity and correct program execution.
8
9TaskPool is well-suited for individual, independent tasks. Therefore, it is recommended for scenarios where synchronous tasks are relatively independent, such as a series of static methods or methods implemented using a singleton pattern. Conversely, if synchronous tasks are interdependent, Worker is the better choice, especially when methods rely on class objects.
10
11
12## Using TaskPool for Independent Synchronous Tasks
13
14TaskPool is ideal for scheduling independent tasks or when a series of tasks is implemented as static methods. It is also suitable when unique handles or class objects can be constructed via a singleton pattern and used across different task threads.
15
16> **NOTE**
17>
18> Due to the memory isolation feature of the [actor model](multi-thread-concurrency-overview.md#actor-model) between threads, regular singletons cannot be shared across threads. This issue can be solved by exporting singletons through sendable modules.
19
201. Define a concurrent function to implement service logic.
21
222. Create a [task](../reference/apis-arkts/js-apis-taskpool.md#task), and execute the task using the [execute()](../reference/apis-arkts/js-apis-taskpool.md#taskpoolexecute-1) interface.
23
243. Perform operations on the task result.
25
26In the following example, the service logic uses TaskPool to call related synchronous methods. First, define the concurrent function **taskpoolFunc**, which must be decorated with [@Concurrent](taskpool-introduction.md#concurrent-decorator). Then, define the function **mainFunc**, which creates tasks, executes them, and performs operations on the results returned by the tasks.
27
28
29```ts
30// Index.ets code
31import { taskpool} from '@kit.ArkTS';
32
33// Step 1: Define a concurrent function to implement service logic.
34@Concurrent
35async function taskpoolFunc(num: number): Promise<number> {
36  // Implement the corresponding functionality based on the service logic.
37  let tmpNum: number = num + 100;
38  return tmpNum;
39}
40
41async function mainFunc(): Promise<void> {
42  // Step 2: Create and execute a task.
43  let task1: taskpool.Task = new taskpool.Task(taskpoolFunc, 1);
44  let res1: number = await taskpool.execute(task1) as number;
45  let task2: taskpool.Task = new taskpool.Task(taskpoolFunc, res1);
46  let res2: number = await taskpool.execute(task2) as number;
47  // Step 3: Perform operations on the result returned by the task.
48  console.info("taskpool: task res1 is: " + res1);
49  console.info("taskpool: task res2 is: " + res2);
50}
51
52@Entry
53@Component
54struct Index {
55  @State message: string = 'Hello World';
56
57  build() {
58    Row() {
59      Column() {
60        Text(this.message)
61          .fontSize(50)
62          .fontWeight(FontWeight.Bold)
63          .onClick(async () => {
64            mainFunc();
65          })
66      }
67      .width('100%')
68      .height('100%')
69    }
70  }
71}
72```
73
74
75## Using Worker for Interdependent Synchronous Tasks
76
77When a series of synchronous tasks needs to be scheduled using the same handle, or when they depend on a specific class object that cannot be shared across different task pools, Worker is the appropriate choice.
78
791. Create a Worker object in the UI main thread and receive messages from the Worker thread. DevEco Studio supports generation of Worker templates with a single click. In the corresponding {moduleName} directory, right-click anywhere and choose **New > Worker** to automatically generate the Worker template files and configuration information.
80
81    ```ts
82    // Index.ets
83    import { worker } from '@kit.ArkTS';
84
85    @Entry
86    @Component
87    struct Index {
88      @State message: string = 'Hello World';
89
90      build() {
91        Row() {
92          Column() {
93            Text(this.message)
94              .fontSize(50)
95              .fontWeight(FontWeight.Bold)
96              .onClick(() => {
97                let w: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts');
98                w.onmessage = (): void => {
99                  // Receive results from the Worker thread.
100                }
101                w.onAllErrors = (): void => {
102                  // Receive error messages from the Worker thread.
103                }
104                // Send a Set message to the Worker thread.
105                w.postMessage({'type': 0, 'data': 'data'})
106                // Send a Get message to the Worker thread.
107                w.postMessage({'type': 1})
108                // ...
109                // Destroy the thread based on actual service requirements.
110                w.terminate()
111              })
112          }
113          .width('100%')
114        }
115        .height('100%')
116      }
117    }
118    ```
119
120
1212. Bind the Worker object in the Worker thread and process the synchronous task logic.
122
123    ```ts
124    // handle.ts code
125    export default class Handle {
126      syncGet() {
127        return;
128      }
129
130      syncSet(num: number) {
131        return;
132      }
133    }
134    ```
135
136    ```ts
137    // MyWorker.ts code
138    import { worker, ThreadWorkerGlobalScope, MessageEvents } from '@kit.ArkTS';
139    import Handle from './handle'  // Import the handle.
140
141    let workerPort : ThreadWorkerGlobalScope = worker.workerPort;
142
143    // Handle that cannot be transferred. All operations depend on this handle.
144    let handler: Handle = new Handle()
145
146    // onmessage() logic of the Worker thread.
147    workerPort.onmessage = (e : MessageEvents): void => {
148     switch (e.data.type as number) {
149      case 0:
150       handler.syncSet(e.data.data);
151       workerPort.postMessage('success set');
152       break;
153      case 1:
154       handler.syncGet();
155       workerPort.postMessage('success get');
156       break;
157     }
158    }
159    ```
160