为有牺牲多壮志,敢教日月换新天。

HarmonyOS:Node-API典型场景开发(1)

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ 
➤GitHub地址:https://github.com/strengthen
➤原文地址:https://www.cnblogs.com/strengthen/p/18504101
➤如果链接不是为敢技术的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

一、典型开发场景概述
开发者在使用Node-AP|进行Native侧业务开发时,经常会面临同步任务开发、异步任务开发以及线程安全开发等典型场景。
1、使用Node-API进行同步任务开发:在该场景中,应用侧在调用Native接口后,将会被阻塞等待Native侧计算结果。比如,应用侧需要读取文件,同步模式下,应用侧程序将会一直等待Native侧文件读取完成,然后再继续运行。
2、使用Node-API进行异步任务开发:在该场景中,应用侧在调用Native接口后,将会收到临时结果,并继续执行UI操作。Native侧将异步执行业务逻辑,不阻塞应用侧。比如,应用侧需要读取文件,异步模式下,应用侧程序将不会等待Native侧文件读取完成,并继续运行。
3、使用Node-API进行线程安全开发:ArkTS天然线程安全,而Native侧代码需要开发者自行保障线程安全。Native侧C++子线程不可跨线程直接访问ArkTS对象。Node-AP提供了可保障线程异步执行与通信安全的机制:线程安全函数。

二、使用Node-API进行同步任务开发
1、Node-API同步任务开发支持callback回调模式,具体方式由开发者决定,通过是否传递callback回调函数进行区分。
callBack回调下,同步任务的时序交互流程:首先应用侧调用Native接口并传入参数,然后在Native接口中过通过使用相应的API进行参数解析,参数类型转换,业务逻辑运算,结果类型转换。最后通过回调callback,将业务计算结果反馈到应用,刷新UI界面。
(1)、napi_get_cb_info:获取应用侧传入的参数。
(2)、napi_get_value_double:Node-API到C的类型转换。
(3)、调用业务代码,计算结果。
(4)、napi_create_double: C到Node-API的类型转换。
(5)、napi_call_function: Node-API回调ArkTS应用。

 2、同步任务开发实现-callback方法:

非callback模式下的开发在前面的文章已经讲解:《HarmonyOS:使用Node-API实现ArkTS与C/C++跨语言交互》

callback模式下的同步任务开发:
(1)、ArkTS应用侧开发中:首先导入包含Native业务逻辑的动态库libentry.so,并返回一个ArkTS对象testNapi。然后通过testNapi对象调用Native接口传入callback回调进行业务计算。

(2)、导出Native接口:声明一个ArkTS接口用于映射Native侧C++接口,并用export进行导出,

(3)、Native接口实现:解析ArkTS应用侧传入的参数,将参数从napi_value类型转换为double类型,然后进行业务处理,将两数相加结果转换为napi_value,最后通过回调返回结果到应用。

三、使用Node-API进行异步任务开发
1、异步任务开发适用场景:Node-API异步任务开发主要用于执行耗时操作的场景中使用,以避免阻塞主线程,确保应用程序的性能和响应性能。如下图:
(1)、文件操作:读取大型文件,避免阻塞主线程。
(2)、网络请求:网络请求等待,提高响应性能。
(3)、数据库操作:数据库查询写入,提高并发性能。
(4)、图形处理:复杂图像算法,提高实时性能。

2、Node-API异步任务的机制原理。
Node-API通过创建一个异步工作项来实现异步任务开发。其底层机制是基于libuv异步库来实现的。
Native侧开发者将要实现的部分:
(1)、定义execute回调用以执行业务逻辑。
(2)、定义complete回调用以返回结果到应用。
(3)、napi_create_async_work创建异步工作项,注册绑定回调。
(4)、napi_queue_async_work将异步工作项置入队列,等待系统调度。
(5)、返回临时空值到应用,避免ArkTS侧被阻塞。
(6)、等待调度。
在Native接口中将异步工作项置入队列的动作,实际上是通过uv_queue_work异步任务加入libuv线程池队列,当系统调度work子线程,将会执行execute回调进行业务计算,在execute回调执行结束后,将会通过uv_async_send,将complete回调抛到EventLoop事件循环中,等待事件调度。在EventLoop子线程中,将会执行complete回调调用Node-API接口,将excute回调执行结果返回到应用。

3、Callback异步方式交互流程。

(1)、异步方式与同步方式的区别在于,同步方式中所有代码的处理都在ArkTS主线程中完成,而异步方式中的所有代码在多线程中完成。

(2)、Node-API异步接口实现支持Callback方式和Promise方式,具体使用哪种方式由应用开发者决定,通过是否传递callback函数进行区分。

callback模式下的异步任务是怎样进行交互的:ArkTS应用侧调用运行在主线程上的Native接口,在Native接口中,通过使用相应的API进行参数解析,创建callback引用置入上下文,创建异步工作项,并将任务置入队列,等待系统调度给应用侧返回临时空值,避免阻塞应用侧。当work子线程被调度后,将会执行execute回调,执行异步业务逻辑,并将计算结果写入上下文。在EventLoop子线程中,当事件被调度将会执行complete回调。在complete回调中,将会解析上下文,通过napi_get_reference_value解引用获取callback,最后通过napi_call_function接口触发回调。将异步结果返回到应用侧刷新UI界面。

4、Promise异步方式交互流程。

(1)、Promise异步模型时序交互流程与callback异步模型基本一致。具体差异在于promise方式不需要callback层层回调,而是通过对象解析的方式进行数据反馈。

(2)、promise模型下Native接口会创建promise对象返回给应用侧而非临时空值。Promise模型下,complete回调将会通过napi_resolve_deferred 接口,解析异步结果到应用侧而非触发回调。

5、异步任务的开发实现-callback异步方法。

(1)、ArkTS应用侧开发:首先导入包含Native业务逻辑的动态库,并返回一个ArkTS对象testNapi,然后通过testNapi对象调用Native接口传入callback回调进行业务计算。

(2)、导出Native接口:声明一个ArkTS接口用以映射Native侧C++接口,并用export进行导出。

(3)、Execute回调实现:主要执行业务逻辑,也就是将两数相加并将结果置入上下文。

(4)、Complete回调实现:将会执行解析上下文数据,将callback解引用,结果类型转换,然后通过napi_call_function触发callback回调,将结果返回到ArkTS应用侧,最后还需要销毁上下文数据,释放内存。

(5)、Native接口实现:将主要实现解析ArkTS侧传入的参数,将参数类型从napi_value转换为double,分配上下文内存空间,将参数写入上下文。然后给应用侧传入的callback回调创建引用,创建异步工作项,注册绑定execute和complete两个回调,将异步任务入队,等待系统调度,最后返回临时空值到应用避免阻塞应用侧。

四、使用Node-API进行线程安全开发
1、ArkTS天然线程安全,而Native侧代码需要开发者自行保障线程安全。Node-API接口只能在ArkTS主线程上进行调用。
2、当C++子线程需要访问ArkTS对象时,这些子线程是需要与ArkTS主线程进行通信才能完成的。
3、Node-API线程安全开发主要用于多线程之间进行同步、异步、通信的安全保障,以避免出现竞争或死锁现象。比如:异步计算、多线程数据共享、多线程同步以及安全通信等场景,都可以使用线程安全机制来进行开发。
4、线程安全开发的适用场景:
(1)、异步计算:耗时IO操作,提高响应速度。
(2)、数据共享:多个线程共访同一资源,避免竞争或者死锁。
(3)、多线程通信:保障线程通信安全。
(4)、多线程同步:保障线程同步正确。

 5、线程安全机制等原理:Node-API提供了类型napithreadsafe_function(线程安全函数)以及创建、销毁和调用该类型对象的API来完成线程安全开发。

其底层实现机制是基于libuv异步库来实现的。
Native侧开发者将要实现的部分:

(1)、定义线程安全回调,用以反馈结果到应用侧。

(2)、定义C++子线程执行函数,用以执行业务逻辑和调用线程安全函数对象。

(3)、napi_create_threadsafe_function,创建线程安全函数对象,注册绑定回调。

(4)、创建C++子线程,等待系统调度,

(5)、返回临时空值到应用,避免ArkTS侧被阻塞。

(6)、等待调度。

在创建线程安全函数时,

(1)、会通过uv_async_init接口,将处理回调与线程异步通信句柄进行绑定。

(2)、当C++子线程被调度后将执行业务计算。

(3)、同时通过napi_call_threadsafe_function接口。

(4)、将线程安全回调call_js_cb抛到EventLoop事件循环。

(5)、在EventLoop子线程中将会执行call_js_cb回调。

(6)、调用Node-API接口将异步执行结果返回到应用。

 6、线程安全的时序交互流程:

(1)、ArkTS应用侧调用运行在主线程上的Native接口。

(2)、在Native接口中通过使用相应的API进行参数解析。

(3)、创建线程安全函数对象。

(4)、创建C++子线程,等待系统调度。

(5)、给应用侧返回临时空值,避免阻塞应用侧。

线程调度:

(1)、当C++子线程被调用将会执行异步业务逻辑,

(2)、并将计算结果写入上下文。

(3)、通过napi_call_threadsafe_function接口

(4)、将call_js_cb回调到事件循环。

当事件被调度,会执行call_js_cb回调:

(1)、解析上下文数据。

(2)、通过napi_call_function接口触发回调。

(3)、将异步结果返回到应用侧,刷新UI界面。

 7、线程安全开发实践:

(1)、ArkTS应用侧开发:导入包含Native业务逻辑的动态库,并返回一个ArkTS对象的testNapi。然后通过testNapi对象调用Native接口传入callback回调进行业务计算。

(2)、导出Native接口:声明一个ArkTS接口,用于映射Native侧C++接口并用export进行导出。

(3)、C++子线程执行函数:主要执行业务逻辑,示例代码中也是将两数相加,并将结果置入上下文。同时调用线程安全函数将回调任务抛到EventLoop事件循环中。

(4)、Call_js_cb回调实现:将会执行解析上下文数据,结果类型转换为napi_value,通过napi_call_function触发callback回调,将结果反馈到ArkTS应用侧,最后需要销毁上下文数据释放内存。

(5)、Native接口实现:解析ArkTS侧传入的参数,分配上下文内存空间,将参数写入上下文,创建线程安全函数对象,注册绑定callback和call_js_cb回调。创建C++子线程,等待系统调度,最后返回临时空值到应用,避免阻塞。

参考链接:示例代码

posted @ 2024-10-26 15:12  为敢技术  阅读(10)  评论(0编辑  收藏  举报