1# 同步任务开发指导 (TaskPool和Worker)
2
3
4同步任务是指在多个线程之间协调执行的任务,其目的是确保多个任务按照一定的顺序和规则执行,例如使用锁来防止数据竞争。
5
6
7同步任务的实现需要考虑多个线程之间的协作和同步,以确保数据的正确性和程序的正确执行。
8
9由于TaskPool偏向于单个独立的任务,因此当各个同步任务之间相对独立时推荐使用TaskPool,例如一系列导入的静态方法,或者单例实现的方法。如果同步任务之间有关联性,则需要使用Worker,例如无法单例创建的类对象实现的方法。
10
11
12## 使用TaskPool处理同步任务
13
14当调度独立的任务,或者一系列任务为静态方法实现,或者可以通过单例构造唯一的句柄或类对象,可在不同任务线程之间使用时,推荐使用TaskPool。
15
16> **说明:**
17>
18> 由于[Actor模型](multi-thread-concurrency-overview.md#actor模型)不同线程间内存隔离的特性,普通单例无法在不同线程间使用。可以通过共享模块导出单例解决该问题。
19
201. 定义并发函数,实现业务逻辑。
21
222. 创建任务[Task](../reference/apis-arkts/js-apis-taskpool.md#task),通过[execute()](../reference/apis-arkts/js-apis-taskpool.md#taskpoolexecute-1)接口执行该任务。
23
243. 对任务返回的结果进行操作。
25
26如下示例中业务使用TaskPool调用相关同步方法的代码,首先定义并发函数taskpoolFunc,需要注意必须使用[@Concurrent装饰器](taskpool-introduction.md#concurrent装饰器)装饰该函数;其次定义函数mainFunc,该函数功能为创建任务,执行任务并对任务返回的结果进行操作。
27
28
29```ts
30// Index.ets代码
31import { taskpool} from '@kit.ArkTS';
32
33// 步骤1: 定义并发函数,实现业务逻辑
34@Concurrent
35async function taskpoolFunc(num: number): Promise<number> {
36  // 根据业务逻辑实现相应的功能
37  let tmpNum: number = num + 100;
38  return tmpNum;
39}
40
41async function mainFunc(): Promise<void> {
42  // 步骤2: 创建任务并执行
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  // 步骤3: 对任务返回的结果进行操作
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## 使用Worker处理关联的同步任务
76
77当一系列同步任务需要使用同一个句柄调度,或者需要依赖某个类对象调度,无法在不同任务池之间共享时,需要使用Worker。
78
791. 在UI主线程中创建Worker对象,同时接收Worker线程发送回来的消息。DevEco Studio支持一键生成Worker,在对应的{moduleName}目录下任意位置,点击鼠标右键 > New > Worker,即可自动生成Worker的模板文件及配置信息。
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                  // 接收Worker子线程的结果
100                }
101                w.onerror = (): void => {
102                  // 接收Worker子线程的错误信息
103                }
104                // 向Worker子线程发送Set消息
105                w.postMessage({'type': 0, 'data': 'data'})
106                // 向Worker子线程发送Get消息
107                w.postMessage({'type': 1})
108                // ...
109                // 根据实际业务,选择时机以销毁线程
110                w.terminate()
111              })
112          }
113          .width('100%')
114        }
115        .height('100%')
116      }
117    }
118    ```
119
120
1212. 在Worker线程中绑定Worker对象,同时处理同步任务逻辑。
122
123    ```ts
124    // handle.ts代码
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代码
138    import { worker, ThreadWorkerGlobalScope, MessageEvents } from '@kit.ArkTS';
139    import Handle from './handle';  // 返回句柄
140
141    let workerPort : ThreadWorkerGlobalScope = worker.workerPort;
142
143    // 无法传输的句柄,所有操作依赖此句柄
144    let handler: Handle = new Handle()
145
146    // Worker线程的onmessage逻辑
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