diff --git a/OAT.xml b/OAT.xml index 6b94ea812aa1e444b6b52337bf0eec17d79dcc19..8b1ee7c6171ed83c2ce05e6858416eb902b9b986 100644 --- a/OAT.xml +++ b/OAT.xml @@ -169,6 +169,8 @@ Note:If the text contains special characters, please escape them according to th + + diff --git a/code/ArkTS1.2/ParallelSample/README.md b/code/ArkTS1.2/ParallelSample/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9b05cd8f90402ba0e9f964d505b081b5aa587b31 --- /dev/null +++ b/code/ArkTS1.2/ParallelSample/README.md @@ -0,0 +1,89 @@ +# 并行化处理 + +### 介绍 + +### EAWorker介绍 +EACoroutine特性是为开发者提供一个能够独占线程的协程,用于执行特定的任务。 +ArkTS演进的世界里只有协程的概念,用户创建的并发/异步任务实际通过不同的协程执行,当用户抛出重载任务会导致某个协程执行任务耗时过长影响系统调用,或用户期望有一个能够独立执行特定任务的协程,因此此处补充独占协程(Exclusive ArkTS Coroutine)。 + +### EAWorker工作机制 +在创建 EAWorker 时,可选择是否启用 interop 功能。不过,创建 EAWorker 会产生一定的内存和性能开销,而且大量创建 EAWorker 会抢占系统线程资源,因此需要对 EAWorker 的创建数量进行限制。 +若要创建 EAWorker,可调用 EAWorker 构造函数并传入一个布尔值参数,该参数用于控制是否启用 interop 功能,此功能仅在混合虚拟机环境下生效。 + +在混合虚拟机环境中,创建EAWorker,EAWorker对象可以调用run方法向EAWorker抛任务,利用EACoroutine设置并行化使用场景。 +创建打开interop的EAWorker对象,创建多个任务,用EAWorker对象并行地执行这些任务。观察结果是否和预期一致。 + +### AsyncLock(异步锁) + +为了解决多并发实例间的数据竞争问题,ArkTS语言基础库引入了异步锁能力。为了开发者的开发效率,AsyncLock对象支持跨并发实例引用传递。 + +使用异步锁的方法需要标记为async,调用方需要await修饰调用,才能保证时序正确。因此会导致外层调用函数全部标记成async。 + +### TaskPool介绍 +任务池(TaskPool)作用是为应用程序提供一个多线程的运行环境,降低整体资源的消耗、提高系统的整体性能,且无需关心线程实例的生命周期。 + +### TaskPool工作机制 +该接口设计简洁,易于使用,支持对任务进行执行、取消操作,同时具备指定任务优先级的能力。此外,通过系统统一的线程管理机制,结合动态调度和负载均衡算法,能够有效节省系统资源。 +当长时间没有任务需要分发时,工作线程会自动缩容,从而减少工作线程的数量。 + +### 效果预览 + +效果如下所示: + +|EAWorker|taskPool| +|--------------------------------|--------------------------------| +|![Alt text](entry/src/main/resources/base/media/eaworker.PNG)|![Alt text](entry/src/main/resources/base/media/taskpool.PNG)| + +使用说明 + +1. 在EAworker界面,依次点击蓝色按钮会在对应下方预期结果部分打印出对应日志; +2. 在taskPool界面,依次点击蓝色按钮会在对应下方预期结果部分打印出对应日志; + + +### 工程目录 + +``` +entry/src/main/ets/ +|---pages +| |---index.ets // 并行化首页 +``` + +### 具体实现 + +* EAWorker 源码参考: [Index.ets](entry/src/main/ets/pages/Index.ets) + * 不同线程共同操作一个函数-加锁 在[Index.ets](entry/src/main/ets/pages/Index.ets)中创建EAWoker线程,调用foo(),并且foo()加锁; + * 不同线程共同操作一个函数-不加锁 在[Index.ets](entry/src/main/ets/pages/Index.ets)中创建EAWoker线程,调用fooUnlock(); + * 不同线程操作不同函数-加锁 在[Index.ets](entry/src/main/ets/pages/Index.ets)中创建EAWoker线程,调用fooTest() fooTest2() fooTest3(),并且fooTest() fooTest2() fooTest3() 函数都加锁; + * 不同线程操作不同函数-不加锁 在[Index.ets](entry/src/main/ets/pages/Index.ets)中创建EAWoker线程,调用fooTestUnlock() fooTestUnlock2() fooTestUnlock3(); + * 不同线程共享一个容器 在[Index.ets](entry/src/main/ets/pages/Index.ets)中创建EAWoker线程 map容器,调用fooMapTest() fooMapTest2(); + * 不同线程操作一个文件 在[Index.ets](entry/src/main/ets/pages/Index.ets)中创建EAWoker线程,主线程调用createFileTest() 子线程调用readFile(); +* taskPool 源码参考: [Index.ets](entry/src/main/ets/pages/Index.ets) + * 执行一组有关联的任务 在[Index.ets](entry/src/main/ets/pages/Index.ets)中调用taskTest()函数创建一组TaskPoll线程; + * 任务优先级 在[Index.ets](entry/src/main/ets/pages/Index.ets)中 调用concurrentFunc()函数循环创建TaskPoll线程; + * 并发函数计算两数之和 在[Index.ets](entry/src/main/ets/pages/Index.ets)中 调用concurrentFuncAdd()函数创建TaskPoll线程计算两数之和; + +### 相关权限 + +无 + +### 依赖 + +无 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:Phone; +2. 本示例为Stage模型,支持API20版本SDK,SDK版本号(API Version 20),镜像版本号(5.0.1.57)。 +3. 本示例需要使用DevEco Studio 版本号(6.0.0.6)版本才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo code/ArkTS1.2/ParallelSample/ > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git +git pull +``` \ No newline at end of file diff --git a/code/ArkTS1.2/ParallelSample/entry/src/main/ets/pages/Index.ets b/code/ArkTS1.2/ParallelSample/entry/src/main/ets/pages/Index.ets index 4a3a6273e6020a1d3e89c598b2c8ae0c2429f382..515ec255f12e61987bb3394916f94e9400bab278 100644 --- a/code/ArkTS1.2/ParallelSample/entry/src/main/ets/pages/Index.ets +++ b/code/ArkTS1.2/ParallelSample/entry/src/main/ets/pages/Index.ets @@ -38,7 +38,7 @@ import { ButtonAttribute, ClickEvent, UserView, - Row, + Row,$r } from "@ohos.arkui.component" // TextAttribute should be insert by ui-plugins import { State, @@ -78,20 +78,20 @@ function createFileTest(fileName: string, context: string): void { @Component struct MyStateSample { - @State stringTest1LockSame: string = "预期结果"; - @State stringTest1Unlock: string = "预期结果"; - @State messageString: string = "加锁"; - @State messageStringUnlock: string = "不加锁"; - @State mapString: string = "预期结果"; - messageStringTmp: string = "预期结果"; - messageStringTmpUnlock: string = "预期结果"; - stringTest1TmpLockSame: string = "预期结果"; - stringTest1TmpUnlock: string = "预期结果"; - @State stringTest2: string = "预期结果"; - @State stringFile: string = "预期结果"; - @State priorityString: string = "预期结果"; - @State addString: string = "预期结果 "; - @State taskGroupString: string = "预期结果 "; + @State stringTest1LockSame: string = ""; + @State stringTest1Unlock: string = ""; + @State messageString: string = ""; + @State messageStringUnlock: string = ""; + @State mapString: string = ""; + messageStringTmp: string = ""; + messageStringTmpUnlock: string = ""; + stringTest1TmpLockSame: string = ""; + stringTest1TmpUnlock: string = ""; + @State stringTest2: string = ""; + @State stringFile: string = ""; + @State priorityString: string = ""; + @State addString: string = " "; + @State taskGroupString: string = " "; async readFile(fileName: string): Promise { await lockFile.lockAsync(() => { @@ -229,15 +229,15 @@ struct MyStateSample { } priorityLOW() { - this.priorityString += "低"; + this.priorityString += "L"; } priorityHIGH() { - this.priorityString += "高"; + this.priorityString += "H"; } priorityMEDIUM() { - this.priorityString += "中"; + this.priorityString += "M"; } concurrentFunc() { @@ -261,7 +261,7 @@ struct MyStateSample { Column() { Column() { Text("-------------------EAWorker------------------").width("100%") - Button("EAWorker-不同线程共同操作一个函数-加锁") + Button($r('app.string.EAWorkerButtonTest')) .onClick((e: ClickEvent) => { let eaw: EAWorker = new EAWorker(true); let eaw2: EAWorker = new EAWorker(true); @@ -282,11 +282,11 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:资源竞争,可能会出现交替打印").height(NUM_50) + Text($r('app.string.EAWorkerTextTest')).height(NUM_50) Text(this.messageStringUnlock).width("90%") } - Button("EAWorker-不同线程共同操作一个函数-不加锁") + Button($r('app.string.EAWorkerButtonTest2')) .onClick((e: ClickEvent) => { let eaw: EAWorker = new EAWorker(true); let eaw2: EAWorker = new EAWorker(true); @@ -306,13 +306,13 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:资源竞争,可能会出现交替打印").height(NUM_50) + Text($r('app.string.EAWorkerTextTest2')).height(NUM_50) Text(this.messageStringUnlock).width("90%") } }.height(NUM_200) Column() { - Button("EAWorker-不同线程操作不同函数-加锁") + Button($r('app.string.EAWorkerButtonTest3')) .onClick((e: ClickEvent) => { let eaw: EAWorker = new EAWorker(true); let eaw2: EAWorker = new EAWorker(true); @@ -329,13 +329,13 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:不会出现交替打印的问题-使用锁").height(NUM_50) + Text($r('app.string.EAWorkerTextTest3')).height(NUM_50) Text(this.stringTest1LockSame).width("90%") } }.height(NUM_200) Column() { - Button("EAWorker-不同线程操作不同函数-不加锁") + Button($r('app.string.EAWorkerButtonTest4')) .onClick((e: ClickEvent) => { let eaw: EAWorker = new EAWorker(true); let eaw2: EAWorker = new EAWorker(true); @@ -352,13 +352,13 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:会出现交替打印的问题-不使用锁").height(NUM_50) + Text("$r('app.string.EAWorkerTextTest4')").height(NUM_50) Text(this.stringTest1Unlock).width("90%") } }.height(NUM_200) Column() { - Button("EAWorker-不同线程共享一个容器") + Button($r('app.string.EAWorkerButtonTest5')) .onClick((e: ClickEvent) => { let eaw: EAWorker = new EAWorker(true); let eaw2: EAWorker = new EAWorker(true); @@ -374,14 +374,13 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:一个线程让map插入100个数据 另一个线程让map删除NUM_50个数据,并且map大小应为NUM_50,目前EAWorker子线程控制不了时序,可能会出现100(先删除空map,后加100数据) ") - .height(NUM_50) + Text($r('app.string.EAWorkerTextTest5')).height(NUM_50) Text(this.mapString).width("90%") } }.height(NUM_200) Column() { - Button("EAWorker-不同线程读写同一个文件") + Button($r('app.string.EAWorkerButtonTest6')) .onClick((e: ClickEvent) => { hilog.info(0x0000, 'testTag', 'On Click'); let path: string = "/data/storage/el2/base/haps/entry/files/test.txt"; @@ -395,14 +394,14 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:一个线程在文件写入文本,另一个线程从文件中读取文本").height(NUM_50) + Text($r('app.string.EAWorkerTextTest6')).height(NUM_50) Text(this.stringFile).width("90%") } }.height(NUM_200) Text("-------------------taskPool------------------").width("100%") Column() { - Button("taskPool-执行一组有关联的任务") + Button($r('app.string.TaskPoolButtonTest')) .onClick((e: ClickEvent) => { hilog.info(0x0000, 'testTag', 'On Click'); this.taskTest(); @@ -411,13 +410,13 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:任务组中任务全部执行完成后,结果数组统一返回").height(NUM_50) + Text($r('app.string.TaskPoolTextTest')).height(NUM_50) Text(this.taskGroupString).width("90%") } }.height(NUM_200) Column() { - Button('$string:taskPool') + Button($r('app.string.TaskPoolButtonTest2')) .onClick((e: ClickEvent) => { this.concurrentFunc(); }) @@ -425,14 +424,14 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:创建实例可以给第二个参数设置权重,假设有两个多线程任务,可以决定优先执行那一个多线程任务") + Text($r('app.string.TaskPoolTextTest2')).height(NUM_50) .height(NUM_50) Text(this.priorityString).width("90%") } }.height(NUM_200) Column() { - Button("taskPool-计算两数之和") + Button($r('app.string.TaskPoolButtonTest3')) .onClick((e: ClickEvent) => { hilog.info(0x0000, 'testTag', 'On Click'); this.concurrentFuncAdd(); @@ -441,7 +440,7 @@ struct MyStateSample { .backgroundColor(0x317aff) .width("80%") Column() { - Text("说明:输入2和10输出 12") + Text($r('app.string.TaskPoolTextTest3')) .height(NUM_50) Text(this.addString).width("90%") } diff --git a/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/element/string.json b/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/element/string.json index fab8be2517841316b12c988ff58d13340c2962f0..69c99dba858600a285b06c9ef9a81da3e2939ed0 100644 --- a/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/element/string.json +++ b/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/element/string.json @@ -13,8 +13,88 @@ "value": "label" }, { - "name": "taskPool", + "name": "LOW", + "value": "低" + }, + { + "name": "MEDIUM", + "value": "中" + }, + { + "name": "HIGH", + "value": "高" + }, + { + "name": "EAWorkerButtonTest", + "value": "EAWorker-不同线程共同操作一个函数-加锁" + }, + { + "name": "EAWorkerTextTest", + "value": "说明:不会出现交替打印的问题" + }, + { + "name": "EAWorkerButtonTest2", + "value": "EAWorker-不同线程共同操作一个函数-不加锁" + }, + { + "name": "EAWorkerTextTest2", + "value": "说明:资源竞争,可能会出现交替打印" + }, + { + "name": "EAWorkerButtonTest3", + "value": "EAWorker-不同线程操作不同函数-加锁" + }, + { + "name": "EAWorkerTextTest3", + "value": "说明:不会出现交替打印的问题" + }, + { + "name": "EAWorkerButtonTest4", + "value": "EAWorker-不同线程操作不同函数-不加锁" + }, + { + "name": "EAWorkerTextTest4", + "value": "说明:会出现交替打印的问题-不使用锁" + }, + { + "name": "EAWorkerButtonTest5", + "value": "EAWorker-不同线程共享一个容器" + }, + { + "name": "EAWorkerTextTest5", + "value": "说明:一个线程让map插入100个数据 另一个线程让map删除50个数据,并且map大小应为50,目前EAWorker子线程控制不了时序,可能会出现100(先删除空map,后加100数据)" + }, + { + "name": "EAWorkerButtonTest6", + "value": "EAWorker-不同线程读写同一个文件" + }, + { + "name": "EAWorkerTextTest6", + "value": "说明:一个线程在文件写入文本,另一个线程从文件中读取文本" + }, + { + "name": "TaskPoolButtonTest", + "value": "taskPool-执行一组有关联的任务" + }, + { + "name": "TaskPoolTextTest", + "value": "说明:任务组中任务全部执行完成后,结果数组统一返回" + }, + { + "name": "TaskPoolButtonTest2", "value": "taskPool-任务优先级" + }, + { + "name": "TaskPoolTextTest2", + "value": "说明:创建实例可以给第二个参数设置权重,假设有两个多线程任务,可以决定优先执行那一个多线程任务" + }, + { + "name": "TaskPoolButtonTest3", + "value": "taskPool-计算两数之和" + }, + { + "name": "TaskPoolTextTest3", + "value": "说明:输入2和10输出 12" } ] } \ No newline at end of file diff --git a/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/media/eaworker.PNG b/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/media/eaworker.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d31de1b819449588d5044742b503f2754519ebe4 Binary files /dev/null and b/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/media/eaworker.PNG differ diff --git a/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/media/taskpool.PNG b/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/media/taskpool.PNG new file mode 100644 index 0000000000000000000000000000000000000000..bfb24abba16948f1f666ba70e7c5834b4d8f94bd Binary files /dev/null and b/code/ArkTS1.2/ParallelSample/entry/src/main/resources/base/media/taskpool.PNG differ diff --git a/code/ArkTS1.2/ParallelSample/ohosTest.md b/code/ArkTS1.2/ParallelSample/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..31b7c9a06d032d62e4b67c11987d76534f77ecb0 --- /dev/null +++ b/code/ArkTS1.2/ParallelSample/ohosTest.md @@ -0,0 +1,15 @@ +# 并行化使用示例测试用例 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +|-----------------------------------|-------------------------------------|----------------------|------------------------------------|------|------| +| EAWorker-不同线程共同操作一个函数-加锁 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【EAWorker-不同线程共同操作一个函数-加锁】按钮 | 打印日志参考如下:(不会出现交替打印)
*************************@@@@@@@@@@@@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&&&&&&&&& | 否 | Pass | +| EAWorker-不同线程共同操作一个函数-不加锁 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【EAWorker-不同线程共同操作一个函数-不加锁】按钮 | 打印日志参考如下:(可能会出现交替打印)
&&&&&&&&&&&&&&&&&&&&&&&*&*&&&&&&&&*****************************************@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | 否 | Pass | +| EAWorker-不同线程操作不同函数-加锁 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【EAWorker-不同线程操作不同函数-加锁】按钮 | 打印日志参考如下:
111111111111111111111111133333333333333333333333332222222222222222222222222 | 否 | Pass | +| EAWorker-不同线程操作不同函数-不加锁 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【EAWorker-不同线程操作不同函数-加锁】按钮 | 打印日志参考如下:
1111111111111111131333133333333333323222222222222222222222 | 否 | Pass | +| EAWorker-不同线程共享一个容器 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【EAWorker-不同线程共享一个容器】按钮 | 显示计算结果:
50或100 | 否 | Pass | +| EAWorker-不同线程读写同一个文件 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【EAWorker-不同线程读写同一个文件】按钮 | 打印日志如下:
com.samples.EAWorker successfully launched | 否 | Pass | +| taskPool-执行一组有关联的任务 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【taskPool-执行一组有关联的任务】按钮 | 打印日志如下:
[100,200,300][10,20,30] | 否 | Pass | +| taskPool-任务优先级 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【taskPool-任务优先级】按钮 | 打印日志如下:
HMHHHHHMHHHHMMMLMMMMMLLLLLLLLL | 否 | Pass | +| taskPool-计算两数之和 | 1. 需在真机测试
2. 构建并安装测试hap | 点击【taskPool-计算两数之和】按钮 | 打印日志如下:
12 | 否 | Pass | \ No newline at end of file