1# CPU Intensive Task Development (TaskPool and Worker)
2
3
4CPU intensive tasks are tasks that occupy a significant amount of system computing resources and that may block other tasks in the same thread. Example CPU intensive tasks are image processing, video encoding, and data analysis.
5
6
7To improve CPU utilization and application response speeds, use multithread concurrency in processing CPU intensive tasks.
8
9
10If a task can be completed in a background thread within 3 minutes, you are advised to use TaskPool. Otherwise, use Worker.
11
12The following uses histogram processing and a time-consuming model prediction task in the background as examples.
13
14
15## Using TaskPool to Process Histograms
16
171. Implement the logic of image processing.
18
192. Segment the data, and initiate associated task scheduling through task groups.
20   Create a [task group](../reference/apis-arkts/js-apis-taskpool.md#taskgroup10), call [addTask()](../reference/apis-arkts/js-apis-taskpool.md#addtask10) to add tasks, and call [execute()](../reference/apis-arkts/js-apis-taskpool.md#taskpoolexecute10) to execute the tasks in the task group at a [a high priority](../reference/apis-arkts/js-apis-taskpool.md#priority). After all the tasks in the task group are complete, the histogram processing result is returned simultaneously.
21
223. Summarize and process the result arrays.
23
24```ts
25import { taskpool } from '@kit.ArkTS';
26
27@Concurrent
28function imageProcessing(dataSlice: ArrayBuffer): ArrayBuffer {
29  // Step 1: Perform specific image processing operations and other time-consuming operations.
30  return dataSlice;
31}
32
33function histogramStatistic(pixelBuffer: ArrayBuffer): void {
34  // Step 2: Perform concurrent scheduling for data in three segments.
35  let number: number = pixelBuffer.byteLength / 3;
36  let buffer1: ArrayBuffer = pixelBuffer.slice(0, number);
37  let buffer2: ArrayBuffer = pixelBuffer.slice(number, number * 2);
38  let buffer3: ArrayBuffer = pixelBuffer.slice(number * 2);
39
40  let group: taskpool.TaskGroup = new taskpool.TaskGroup();
41  group.addTask(imageProcessing, buffer1);
42  group.addTask(imageProcessing, buffer2);
43  group.addTask(imageProcessing, buffer3);
44
45  taskpool.execute(group, taskpool.Priority.HIGH).then((ret: Object) => {
46    // Step 3: Summarize and process the result arrays.
47  })
48}
49
50@Entry
51@Component
52struct Index {
53  @State message: string = 'Hello World'
54
55  build() {
56    Row() {
57      Column() {
58        Text(this.message)
59          .fontSize(50)
60          .fontWeight(FontWeight.Bold)
61          .onClick(() => {
62            let buffer: ArrayBuffer = new ArrayBuffer(24);
63            histogramStatistic(buffer);
64          })
65      }
66      .width('100%')
67    }
68    .height('100%')
69  }
70}
71```
72
73
74## Using Worker for Time-Consuming Model Prediction
75
76The following uses the training of a region-specific house price prediction model as an example. This model can be used to predict house prices in the region based on the house area and number of rooms. The model needs to run for a long time, and each prediction needs to use the previous running result. Due to these considerations, Worker is used for the development.
77
781. In DevEco Studio, add a worker named **MyWorker** to your project.
79
80   ![newWorker](figures/newWorker.png)
81
822. In the main thread, call [constructor()](../reference/apis-arkts/js-apis-worker.md#constructor9) of **ThreadWorker** to create a **Worker** object. The calling thread is the host thread.
83
84    ```ts
85    // Index.ets
86    import { worker } from '@kit.ArkTS';
87
88    const workerInstance: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts');
89    ```
90
913. In the host thread, call [onmessage()](../reference/apis-arkts/js-apis-worker.md#onmessage9) to receive messages from the worker thread, and call [postMessage()](../reference/apis-arkts/js-apis-worker.md#postmessage9) to send messages to the worker thread.
92   For example, the host thread sends training and prediction messages to the worker thread, and receives messages sent back by the worker thread.
93
94    ```ts
95    // Index.ets
96    let done = false;
97
98    // Receive the result from the worker thread.
99    workerInstance.onmessage = (() => {
100      console.info('MyWorker.ts onmessage');
101      if (!done) {
102        workerInstance.postMessage({ 'type': 1, 'value': 0 });
103        done = true;
104      }
105    })
106
107    workerInstance.onerror = (() => {
108      // Receive error information from the worker thread.
109    })
110
111    // Send a training message to the worker thread.
112    workerInstance.postMessage({ 'type': 0 });
113    ```
114
1154. Bind the **Worker** object in the **MyWorker.ts** file. The calling thread is the worker thread.
116
117   ```ts
118   // MyWorker.ts
119   import { worker, ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@kit.ArkTS';
120
121   let workerPort: ThreadWorkerGlobalScope = worker.workerPort;
122   ```
123
1245. In the worker thread, call [onmessage()](../reference/apis-arkts/js-apis-worker.md#onmessage9-1) to receive messages sent by the host thread, and call [postMessage()](../reference/apis-arkts/js-apis-worker.md#postmessage9-2) to send messages to the host thread.
125    For example, the prediction model and its training process are defined in the worker thread, and messages are exchanged with the main thread.
126
127    ```ts
128    // MyWorker.ts
129    // Define the training model and result.
130    let result: Array<number>;
131    // Define the prediction function.
132    function predict(x: number): number {
133     return result[x];
134    }
135    // Define the optimizer training process.
136    function optimize(): void {
137     result = [0];
138    }
139    // onmessage logic of the worker thread.
140    workerPort.onmessage = (e: MessageEvents): void => {
141     // Perform operations based on the type of data to transmit.
142     switch (e.data.type as number) {
143      case 0:
144      // Perform training.
145       optimize();
146      // Send a training success message to the main thread after training is complete.
147       workerPort.postMessage({ type: 'message', value: 'train success.' });
148       break;
149      case 1:
150      // Execute the prediction.
151       const output: number = predict(e.data.value as number);
152      // Send the prediction result to the main thread.
153       workerPort.postMessage({ type: 'predict', value: output });
154       break;
155      default:
156       workerPort.postMessage({ type: 'message', value: 'send message is invalid' });
157       break;
158     }
159    }
160    ```
161
1626. After the task is completed in the worker thread, destroy the worker thread. The worker thread can be destroyed by itself or the host thread.
163
164    Then, call [onexit()](../reference/apis-arkts/js-apis-worker.md#onexit9) in the host thread to define the processing logic after the worker thread is destroyed.
165
166    ```ts
167    // After the worker thread is destroyed, execute the onexit() callback.
168    workerInstance.onexit = (): void => {
169     console.info("main thread terminate");
170    }
171    ```
172
173    Method 1: In the host thread, call [terminate()](../reference/apis-arkts/js-apis-worker.md#terminate9) to destroy the worker thread and stop the worker thread from receiving messages.
174
175    ```ts
176    // Destroy the worker thread.
177    workerInstance.terminate();
178    ```
179
180    Method 2: In the worker thread, call [close()](../reference/apis-arkts/js-apis-worker.md#close9) to destroy the worker thread and stop the worker thread from receiving messages.
181
182    ```ts
183    // Destroy the worker thread.
184    workerPort.close();
185    ```
186