OpenHarmony开发者论坛
标题: ArkTS并发编程常见问题 [打印本页]
作者: 马迪 时间: 2023-12-16 07:42
标题: ArkTS并发编程常见问题
1. 线程间JS对象的数据通信依赖序列化方式,是否存在性能问题
目前线程间JS对象的数据通信依赖序列化、反序列化,耗时与数据量相关(见图示),需要控制传输的数据量,或者采用ArrayBuffer或者SharedArrayBuffer的转移或者共享。2024年会支持Sendable类的转移或共享。
(, 下载次数: 23)
https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/arkts-utils/multi-thread-concurrency-overview.md/
2. Worker可用线程数目少, 部分应用可能超过200个线程。 TaskPool和Worker都无法提供对等的线程数量。
OpenHarmony采用ArkTS开发语言,由于底层线程模型对接了libuv,因此在应用进程启动后,会有多个I/O线程用于I/O操作,JS线程的I/O异步操作,会在I/O线程执行,JS线程可以同时执行其他操作,不存在阻塞等待问题。
同时,ArkTS提供了TaskPool并发API,类似GCD的线程池能力,可以执行任务,而且不需要开发者进行线程生命周期管理。
因此针对需要大量线程的问题,鸿蒙应用的开发建议如下:
- 将多线程任务转变为并发任务,通过TaskPool分发执行
- I/O型任务不需要单独开启线程,而是在当前线程(可以是TaskPool线程)执行
- 少量需要常驻的CPU密集型任务,采用Worker,并且需要控制在8个及以下。
3. 并发任务的调度及时性问题,如何设置Task优先级
- @Concurrent
- function printArgs(args: number): number {
- console.log("printArgs: " + args);
- return args;
- }
- let task: taskpool.Task = new taskpool.Task(printArgs, 100); // 100: test number
- let highCount = 0;
- let mediumCount = 0;
- let lowCount = 0;
- let allCount = 100;
- for (let i: number = 0; i < allCount; i++) {
- taskpool.execute(task, taskpool.Priority.LOW).then((res: number) => {
- lowCount++;
- console.log("taskpool lowCount is :" + lowCount);
- });
- taskpool.execute(task, taskpool.Priority.MEDIUM).then((res: number) => {
- mediumCount++;
- console.log("taskpool mediumCount is :" + mediumCount);
- });
- taskpool.execute(task, taskpool.Priority.HIGH).then((res: number) => {
- highCount++;
- console.log("taskpool highCount is :" + highCount);
- });
- }
复制代码
4. TaskPool和worker分别什么时候使用
两者是不同颗粒度的并发API,Worker更像Thread或者Service维度,Task就是单一任务维度。同时TaskPool简化开发者开发并发程序,支持优先级和取消,并且通过统一管理节省系统资源优化调度。相同点是:在底层并发实例以及交互上,二者本质都是内存隔离模型,参数与范围值的限制是一致的,也有开销。(需注意并发任务粒度)
5. TaskPool不支持线程间通信,只能在最后返回结果,什么时候会支持
2023年12月底会支持TaskPool在过程中回调主线程
示例代码:
- @Concurrent
- async function downloadVideo(){
- // worker线程发送进度回host线程
- taskpool.Task.sendData(res)
- }
- let task = new taskpool.Task(downloadVideo, ...)
- // 基于task实例注册进度条更新UI状态
- task. onReceiveData(((...) => {
- // 更新进度条对象的状态
- this.xxx = res;
- }).bind(barObject))
- await taskpool.execute(task)
复制代码
6. 使用Worker是否会影响TaskPool数量
不影响。两者是独立,Worker是固定数量,当前是8个。TaskPool线程池的数量会根据硬件条件、任务负载等情况动态调整。
7. 是否有线程安全的容器类
因为没有对象直接共享,所以容器都是线程安全的
8. TaskPool,Worker中使用宏任务,微任务是否和JavaScript单线程的事件循环机制一样的?先执行完微任务队列,再执行宏任务?
是的,跟JS线程规范保持一致
9. JS线程通过napi创建的C++线程的处理结果如何返回JS线程?
采用napi_create_threadsafe_function在JS线程创建可被任意线程调用的函数,在C++线程调用napi_call_threadsafe_function可以将结果回调给主线程。
10.Taskpool和Worker的线程个数限制,如果超过会如何?
TaskPool内部会动态调整线程个数,不支持设置数量,只需要往线程池中抛任务,没有上限;Worker的线程个数最多8个,如果Worker超过规定个数,会创建失败。
11. OpenHarmony系统多线程模型是什么样的
ArkTS层主要采用TaskPool,常驻耗时任务可以使用Worker,但是Worker有数量限制,当前是8;Native层建议使用FFRT线程池,pthread不限制。
(, 下载次数: 0)
12. Worker不支持在HAR或HSP中使用
当前暂时不支持,推荐使用TaskPool,预计在2023年12月份支持
13. 复杂JS类对象是否可以支持跨线程共享传递
由于JS是单线程模型,内存隔离,因此普通对象跨线程均采用序列化方式,除此之外,还支持ArrayBuffer的转移传输和SharedArrayBuffer的共享。对于类对象,计划在2023年12月底支持Sendable类实力对象的序列化传递,2024年会支持不可变Sendable对象的转移及共享。
14. 是否支持Context跨线程传递
支持,可以直接将Context作为参数传递
15. 是否支持锁的机制
可以使用SharedArrayBuffer和Atomic支持
- // index.ets
- var sab = new SharedArrayBuffer(32);
- // int32 buffer view for sab
- var i32a = new Int32Array(sab);
- i32a[0]=0;
- let producer = new worker.ThreadWorker("entry/ets/workers/worker_producer.ts")
- producer.postMessage(sab);
- let consumer = new worker.ThreadWorker("entry/ets/workers/worker_consumer.ts")
- consumer.postMessage(sab);
-
-
- // worker_producer.ts
- workerPort.onmessage = function(e : MessageEvents) {
- var sab = e.data;
- // view sab buffer in int32 array
- var i32a = new Int32Array(sab);
- console.info("Producer: received sab");
- // wake customer every 2s.
- setInterval(function() {
- var length = i32a.length;
- for (var i = 1; i < length; i++) {
- i32a[i] = Math.random() * length;
- };
- Atomics.notify(i32a,0,1); // notify customer
- },2000);
- }
-
-
- // worker_consumer.ts
- workerPort.onmessage = function(e : MessageEvents) {
- var sab = e.data;
- var i32a = new Int32Array(sab);
- console.info("Customer: received sab");
- while(true) {
- Atomics.wait(i32a,0,0); //blocked here until be waked.
- var length = i32a.length;
- for (var i = length-1; i > 0; i--) {
- console.info("arraybuffer " + i + " value is " + i32a[i]);
- i32a[i] = i;
- }
- }
- }
复制代码
16.异步线程和主线程比执行更慢吗?
主线程作为UI线程,拥有最高优先级。在负载较高时,执行会更快;负载较低时,效率效率差别不大。
17.ArkTS是否有类似android上的runOnUiThread能力?
不支持runOnUiThread写法。Worker支持通过PostMessage往父线程抛任务。TaskPool支持往父线程发消息,触发任务。
18.ArkTS是否支持类似Java的共享内存模型进行多线程开发吗?
无法做到通过加锁的方式实现多个线程同时对同一个内存对象的同时操作。JS是Actor并发模型,线程间内存隔离,当前只支持SharedArrayBuffer或者Native层对象的共享。2024年3月30号会支持受限的SendableClass类型对象的转移或冻结共享,可以做到只读对象的全局共享,或者对象的转移传输(同一时刻只有一个线程可操作)。
19.ArkTS即将提供的SendableClass有示例代码吗?
- // Sendable通过Concurrent修饰
- @Concurrent
- class SharedClassA {
- state:number = 100
- constructor() {}
- run(data) {}
- }
- @Concurrent
- class SharedClassB {
- constructor() {}
- run(data) {}
- }
- @Concurrent
- class SharedClassC extends SharedClassB {
- obj = new SharedClassA()
- constructor() {}
- run(data) {}
- }
-
- // 普通对象持有Sendable对象
- // Sendable对象持有及继承其他Sendable对象
- obj = {
- "class": new SharedClassC()
- "data": "data_100"
- }
- @Concurrent
- async function func(obj) {
- console.log("async execute task")
- return obj.class.run(obj.class.data)
- }
- let ret = await
复制代码
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) |
Powered by Discuz! X3.5 |