• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# CPU Intensive Task Development
2
3
4CPU intensive tasks occupy lots of system computing resources for a long period of time, during which other events of the thread are blocked. Example CPU intensive tasks are image processing, video encoding, and data analysis.
5
6
7OpenHarmony uses multithread concurrency to process CPU intensive tasks. This improves CPU utilization and application response speed.
8
9
10**Worker** is recommended for a series of synchronous tasks. When there are independent tasks with a huge number or scattered scheduling points, it is inconvenient to use eight worker threads to manage load. In this case, **TaskPool** is recommended. The following uses histogram processing and a time-consuming model prediction task in the background as examples.
11
12
13## Using TaskPool to Process Histograms
14
151. Implement the logic of image processing.
16
172. Segment the data, and use one task to process a data segment.
18
19   Create a [task](../reference/apis/js-apis-taskpool.md#task), and call [execute()](../reference/apis/js-apis-taskpool.md#taskpoolexecute-1) to execute the task. After the task is complete, the histogram processing result is returned simultaneously.
20
213. Process the result.
22
23
24```ts
25import taskpool from '@ohos.taskpool';
26
27@Concurrent
28function imageProcessing(dataSlice: ArrayBuffer) {
29  // Step 1: Perform specific image processing operations and other time-consuming operations.
30  return dataSlice;
31}
32
33function histogramStatistic(pixelBuffer: ArrayBuffer) {
34  // Step 2: Perform concurrent scheduling for data in three segments.
35  let number = pixelBuffer.byteLength / 3;
36  let buffer1 = pixelBuffer.slice(0, number);
37  let buffer2 = pixelBuffer.slice(number, number * 2);
38  let buffer3 = pixelBuffer.slice(number * 2);
39
40  let task1 = new taskpool.Task(imageProcessing, buffer1);
41  let task2 = new taskpool.Task(imageProcessing, buffer2);
42  let task3 = new taskpool.Task(imageProcessing, buffer3);
43
44  taskpool.execute(task1).then((ret: ArrayBuffer[]) => {
45    // Step 3: Process the result.
46  });
47  taskpool.execute(task2).then((ret: ArrayBuffer[]) => {
48    // Step 3: Process the result.
49  });
50  taskpool.execute(task3).then((ret: ArrayBuffer[]) => {
51    // Step 3: Process the result.
52  });
53}
54
55@Entry
56@Component
57struct Index {
58  @State message: string = 'Hello World'
59
60  build() {
61    Row() {
62      Column() {
63        Text(this.message)
64          .fontSize(50)
65          .fontWeight(FontWeight.Bold)
66          .onClick(() => {
67            let data: ArrayBuffer;
68            histogramStatistic(data);
69          })
70      }
71      .width('100%')
72    }
73    .height('100%')
74  }
75}
76```
77
78
79## Using Worker for Time-Consuming Data Analysis
80
81The 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 the prediction will use the previous running result. Due to these considerations, **Worker** is used for the development.
82
831. Add the worker creation template provided on DevEco Studio to your project, and name it **MyWorker**.
84
85   ![newWorker](figures/newWorker.png)
86
872. In the main thread, call [ThreadWorker()](../reference/apis/js-apis-worker.md#threadworker9) to create a **Worker** object. The calling thread is the host thread.
88
89   ```js
90   import worker from '@ohos.worker';
91
92   const workerInstance = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts');
93   ```
94
953. In the host thread, call [onmessage()](../reference/apis/js-apis-worker.md#onmessage9) to receive messages from the worker thread, and call [postMessage()](../reference/apis/js-apis-worker.md#postmessage9) to send messages to the worker thread.
96
97   For example, the host thread sends training and prediction messages to the worker thread, and receives messages sent back by the worker thread.
98
99   ```js
100   // Receive the result of the worker thread.
101   workerInstance.onmessage = function(e) {
102     // data carries the information sent by the main thread.
103     let data = e.data;
104     console.info('MyWorker.ts onmessage');
105     // Perform time-consuming operations in the worker thread.
106   }
107
108   workerInstance.onerror = function (d) {
109     // Receive error information of the worker thread.
110   }
111
112   // Send a training message to the worker thread.
113   workerInstance.postMessage({ 'type': 0 });
114   // Send a prediction message to the worker thread.
115   workerInstance.postMessage({ 'type': 1, 'value': [90, 5] });
116   ```
117
1184. Bind the **Worker** object in the **MyWorker.ts** file. The calling thread is the worker thread.
119
120   ```js
121   import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker';
122
123   let workerPort: ThreadWorkerGlobalScope = worker.workerPort;
124   ```
125
1265. In the worker thread, call [onmessage()](../reference/apis/js-apis-worker.md#onmessage9-1) to receive messages sent by the host thread, and call [postMessage()](../reference/apis/js-apis-worker.md#postmessage9-2) to send messages to the host thread.
127
128   For example, the prediction model and its training process are defined in the worker thread, and messages are exchanged with the main thread.
129
130   ```js
131   import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker';
132
133   let workerPort: ThreadWorkerGlobalScope = worker.workerPort;
134
135   // Define the training model and result.
136   let result;
137
138   // Define the prediction function.
139   function predict(x) {
140     return result[x];
141   }
142
143   // Define the optimizer training process.
144   function optimize() {
145     result = {};
146   }
147
148   // onmessage logic of the worker thread.
149   workerPort.onmessage = function (e: MessageEvents) {
150     let data = e.data
151     // Perform operations based on the type of data to transmit.
152     switch (data.type) {
153       case 0:
154       // Perform training.
155         optimize();
156       // Send a training success message to the main thread after training is complete.
157         workerPort.postMessage({ type: 'message', value: 'train success.' });
158         break;
159       case 1:
160       // Execute the prediction.
161         const output = predict(data.value);
162       // Send the prediction result to the main thread.
163         workerPort.postMessage({ type: 'predict', value: output });
164         break;
165       default:
166         workerPort.postMessage({ type: 'message', value: 'send message is invalid' });
167         break;
168     }
169   }
170   ```
171
1726. 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. Then, call [onexit()](../reference/apis/js-apis-worker.md#onexit9) in the host thread to define the processing logic after the worker thread is destroyed.
173
174      ```js
175      // After the worker thread is destroyed, execute the onexit() callback.
176      workerInstance.onexit = function() {
177        console.info("main thread terminate");
178      }
179      ```
180
181   In the host thread, call [terminate()](../reference/apis/js-apis-worker.md#terminate9) to destroy the worker thread and stop the worker thread from receiving messages.
182
183   ```js
184   // Destroy the worker thread.
185   workerInstance.terminate();
186   ```
187
188   In the worker thread, call [close()](../reference/apis/js-apis-worker.md#close9) to destroy the worker thread and stop the worker thread from receiving messages.
189
190   ```js
191   // Destroy the worker thread.
192   workerPort.close();
193   ```