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  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