0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

單線程也能開發(fā)異步任務(wù)?ACE JS框架到底是如何做到的

話說科技 ? 2021-08-13 17:16 ? 次閱讀

HarmonyOS 2提供了兩種應(yīng)用開發(fā)語言:Java和JS。Java線程特性能夠讓多任務(wù)并行,充分利用硬件資源開發(fā)出高性能的應(yīng)用。而JS卻是一個(gè)單線程語言,無法像Java一樣創(chuàng)建新的Thread,用JS語言開發(fā)是否會(huì)導(dǎo)致硬件資源無法充分利用的情況呢?

本文給大家介紹“ACE JS的單線程異步機(jī)制”就是解決這個(gè)問題的。然而,說到 “單線程”與“異步”,大家可能會(huì)比較疑惑,因?yàn)閱尉€程和異步在概念上是沖突的,單線程無法做到多任務(wù)并發(fā),也就不會(huì)存在異步這種通信機(jī)制。

確實(shí),JS語言本身是無法實(shí)現(xiàn)異步的,但是ACE JS框架卻提供了多線程的宿主環(huán)境,通過消息通信機(jī)制讓JS語言有了異步的屬性,下面我們來詳細(xì)描述其原理。

ACE開發(fā)框架

使用JS開發(fā)HarmonyOS應(yīng)用,使用的開發(fā)框架名為ACE(Ability Cross-Platform Environment),該框架適用于手機(jī)、平板、智慧屏、智慧表、車機(jī)等設(shè)備,具備“一次開發(fā),多端部署”的能力。

ACE框架包括應(yīng)用層(Application)、前端框架層(Framework)、引擎層(Engine)和平臺(tái)適配層(Porting Layer),如下圖所示:

pYYBAGEWOIyATdaWAADtwa2aYQQ444.png

●Application

應(yīng)用層表示開發(fā)者使用JS UI框架開發(fā)的FA應(yīng)用,這里的FA應(yīng)用特指JS FA應(yīng)用。

●Framework

前端框架層主要完成前端頁面解析,以及提供MVVM(Model-View-ViewModel)開發(fā)模式、頁面路由機(jī)制和自定義組件等能力。

●Engine

引擎層主要提供動(dòng)畫解析、DOM(Document Object Model)樹構(gòu)建、布局計(jì)算、渲染命令構(gòu)建與繪制、事件管理等能力。

●Porting Layer

適配層主要完成對(duì)平臺(tái)層進(jìn)行抽象,提供抽象接口,可以對(duì)接到系統(tǒng)平臺(tái)。比如:事件對(duì)接、渲染管線對(duì)接和系統(tǒng)生命周期對(duì)接等。

ACE開發(fā)框架的線程模型

poYBAGEWOI2Ae7o0AAD6WYLdZrY885.png

每個(gè)HarmonyOS JS應(yīng)用,都是通過上圖所示的ACE開發(fā)框架進(jìn)行加載渲染的。ACE開發(fā)框架包含了JS線程、UI線程、GPU線程、IO線程,并且在ACE框架外還會(huì)存在一類后臺(tái)任務(wù)線程。

其中GPU線程與IO線程主要是ACE框架初始化與頁面加載渲染的過程需要的,為ACE框架內(nèi)部的專有線程,不會(huì)被應(yīng)用直接操作到,應(yīng)用不需要特別關(guān)注;UI線程、JS線程和后臺(tái)任務(wù)線程會(huì)與應(yīng)用開發(fā)代碼相關(guān),后面著重分析這三個(gè)線程的作用和關(guān)系。

●UI線程:負(fù)責(zé)應(yīng)用界面的繪制刷新,與應(yīng)用的進(jìn)程號(hào)相同,又叫主線程。如果開發(fā)JS+JAVA的混合編程,JAVA PA(Particle Ability)的onStart/onConnect等Ability生命周期回調(diào)便是運(yùn)行在主線程,若在這些生命周期回調(diào)上執(zhí)行耗時(shí)操作則會(huì)導(dǎo)致JS UI的繪制刷新卡住。

●JS線程:應(yīng)用的JS代碼會(huì)被JS引擎解析執(zhí)行,并運(yùn)行在JS線程上,而JS又是單線程語言,所以目前我們工程中看到的所有的JS代碼都會(huì)執(zhí)行在這個(gè)進(jìn)程下唯一的JS線程上。

●后臺(tái)任務(wù)線程:這里是對(duì)ACE框架外部的后臺(tái)線程的一個(gè)統(tǒng)稱,并不單指一個(gè)線程,也并不唯一。后臺(tái)任務(wù)線程包含了Java PA線程、文件操作API、網(wǎng)絡(luò)訪問API內(nèi)部實(shí)現(xiàn)等相關(guān)線程。

下面我們結(jié)合測(cè)試代碼來看一下這3個(gè)線程之間的關(guān)系。

JS線程與UI線程的關(guān)系

為了驗(yàn)證JS線程與UI線程的關(guān)系,我們準(zhǔn)備了一個(gè)實(shí)驗(yàn)性質(zhì)的Demo,主要代碼以及運(yùn)行過程的Log如下:

首先我們?cè)贗DE建立一個(gè)Empty Ablity(JS)模板的HelloWorld工程,在生命周期、按鈕響應(yīng)回調(diào)方法里增加Log以觀察線程情況。剛創(chuàng)建的app.js中Application生命周期默認(rèn)已經(jīng)有Log,無需額外添加。

我們只需要在主界面index.js文件中onInit增加日志:

console.info('page.default onInit');

然后在index.hml中增加一個(gè)button以及會(huì)一直進(jìn)行動(dòng)畫的progress組件:

I'm a button

最后在index.js中增加按鈕點(diǎn)擊響應(yīng)事件以及Log,并且嘗試sleep阻塞js線程:

function sleep(delay) {

for (var t = Date.now(); Date.now() - t <= delay; );

}

onButtonClick() {

console.info('onButtonClick begin');

sleep(1000);

console.info('onButtonClick end');

}

將應(yīng)用運(yùn)行起來,點(diǎn)擊兩次按鈕,得到如下Log:

poYBAGEWOI2AHLLyAAC_IDf7wvk861.png

從輸出的Log中,我們可以看到這個(gè)JS FA進(jìn)程號(hào)為22592,也就是說UI線程是22592;生命周期回調(diào)以及按鈕響應(yīng)均在24077線程,這個(gè)就是JS線程,所以JS線程與UI線程不是同一個(gè)線程。

并且我們嘗試通過sleep方法阻塞JS線程,想觀察JS線程阻塞是否會(huì)影響到UI線程的刷新。最終得出的結(jié)論是無論JS線程sleep多長時(shí)間,UI界面上的progress組件動(dòng)畫一直會(huì)不斷刷新,按鈕也會(huì)有按壓效果變化,所以我們可以推測(cè)JS線程與UI線程的相互調(diào)用應(yīng)該是通過某種消息機(jī)制完成的,而不是阻塞式的調(diào)用。

JS線程與后臺(tái)任務(wù)線程的關(guān)系

ACE JS框架提供了JS FA(Feature Ability)調(diào)用Java PA(Particle Ability)的機(jī)制,該機(jī)制提供了一種通道來傳遞方法調(diào)用、處理數(shù)據(jù)返回以及訂閱事件上報(bào)。我們同樣制作一個(gè)Demo來驗(yàn)證JS線程與Java PA線程的關(guān)系:

在JS中,我們通過FeatureAbility.callAbility拉起并調(diào)用了名為一個(gè)類名為ServiceAbility的Java PA,并拿到返回結(jié)果:

var action = {};

action.bundleName = 'com.blancwu.test';

action.abilityName = 'com.blancwu.test.ServiceAbility';

action.messageCode = 1001;

action.abilityType = 0;

action.syncOption = 0;

console.info('FeatureAbility.callAbility begin' + JSON.stringify(action));FeatureAbility.callAbility(action).then(function (value) {

console.info('FeatureAbility.callAbility async result ' + JSON.stringify(value));

})

console.info('FeatureAbility.callAbilityend'+JSON.stringify(action));

在ServiceAbility的onRemoteRequest中增加Log輸出,并sleep 1秒鐘,以便觀察線程情況與之間關(guān)系:

@Override

public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {

HiLog.info(LABEL_LOG, "onRemoteRequest begin " + code);

if (code == 1001) {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

Map result = new HashMap();

result.put("result", 1);

reply.writeString(ZSONObject.toZSONString(result));

}

HiLog.info(LABEL_LOG, "onRemoteRequest end " + code);

return super.onRemoteRequest(code, data, reply, option);

}

以上代碼完成后,我們進(jìn)行執(zhí)行,得到的Log如下:

pYYBAGEWOI6AYZIJAAHEEAp7qeg938.png

我們觀察到本次運(yùn)行主進(jìn)程(UI線程)號(hào)為4133,JS代碼執(zhí)行在JS線程5887,Java PA響應(yīng)onRemoteRequest執(zhí)行在另一個(gè)后臺(tái)任務(wù)線程5837。通過Log我們看到onRemoteRequst即使阻塞了后臺(tái)任務(wù)線程1s也不會(huì)影響JS線程的并行執(zhí)行以及主線程(UI線程)上動(dòng)畫的刷新,做到了JS線程與后臺(tái)任務(wù)線程異步地執(zhí)行事務(wù)。

JS線程的異步機(jī)制

上面從代碼實(shí)驗(yàn)角度觀察到了JS線程與其他線程的異步關(guān)系,那么JS線程是怎么處理來自其他多個(gè)線程的調(diào)用的呢?我們先來看一下傳統(tǒng)的瀏覽器環(huán)境下的機(jī)制:

pYYBAGEWOJGAV9OgAAN5QOfulTo678.png

上圖中,JS線程中的函數(shù)調(diào)用會(huì)存在于棧(stack)中,棧中的函數(shù)可以調(diào)用瀏覽器環(huán)境提供的WebAPIs,包含了DOM、ajax、timeout等API,這些API會(huì)在瀏覽器環(huán)境提供的另外一個(gè)外部線程執(zhí)行,執(zhí)行完成后會(huì)在任務(wù)隊(duì)列(callback queue)中加入對(duì)應(yīng)的回調(diào)事件(如onClick、onLoad、onDone)。當(dāng)棧中的代碼執(zhí)行完畢,即棧清空后,JS線程又會(huì)通過event loop取出任務(wù)隊(duì)列中的下一個(gè)任務(wù)進(jìn)行執(zhí)行,以此類推完成整個(gè)的程序執(zhí)行。更具體的機(jī)制可以去看阮一峰老師介紹JS EventLoop的文章:

●JS EventLoop介紹

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

HarmonyOS ACE開發(fā)框架同樣遵循上述最基本的EventLoop調(diào)度機(jī)制,并且提供了更多的機(jī)制和API,讓業(yè)務(wù)邏輯可以在外部線程執(zhí)行,包含了上面提到的Java PA以及異步回調(diào)的系統(tǒng)能力API。其中,異步回調(diào)的系統(tǒng)能力API包含如文件系統(tǒng)操作和網(wǎng)絡(luò)操作等,具體大家可以按照我們實(shí)驗(yàn)Demo的方法去嘗試一下。

●參考

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-file-storage-0000000000629445

未來發(fā)展的展望

目前ACE JS應(yīng)用內(nèi)實(shí)現(xiàn)多線程的最佳方式是通過混合編程調(diào)用Java PA方式,但未來純JS應(yīng)用一定會(huì)越來越多,那么,只支持單線程的JS ACE框架的異步API能解決各種復(fù)雜場(chǎng)景的問題嗎?

單線程的JS加上異步API能夠很好解決單個(gè)I/O阻塞的問題,但是如果遇到大量的I/O事件,比如批刪除大量文件,通過for循環(huán)發(fā)起了大量異步任務(wù),也會(huì)降低執(zhí)行效率,甚至阻塞其他異步任務(wù)的執(zhí)行。并且如果要使用JS語言開發(fā)計(jì)算密集型的任務(wù),也無法在唯一的JS線程上進(jìn)行。

這時(shí)就需要一個(gè)真正的JS多線程處理機(jī)制了,雖然目前HarmonyOS 2還未支持,但未來HarmonyOS會(huì)考慮規(guī)劃出與HTML5類似提供支持WebWorker機(jī)制,支持開發(fā)出多線程的JS代碼,提供給應(yīng)用開發(fā)者更多的發(fā)揮空間。

fqj

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4788

    瀏覽量

    68625
  • 單線程
    +關(guān)注

    關(guān)注

    0

    文章

    17

    瀏覽量

    1772
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    工程行業(yè)中如何做到低碳甚至零碳

    低碳的生活方式越來越多地融入我們的日常習(xí)慣當(dāng)中。但是在工程行業(yè)中如何做到低碳甚至零碳呢?
    的頭像 發(fā)表于 10-14 10:31 ?422次閱讀

    js基礎(chǔ)之setTimeout與setInterval原理分析

    個(gè)定時(shí)器,讓函數(shù)在計(jì)時(shí)結(jié)束后再執(zhí)行;后者則是每隔一定的時(shí)間,就啟動(dòng)一次函數(shù)的執(zhí)行。 從原理來看,兩者似乎并不復(fù)雜。但由于JavaScript引擎是單線程的,這就讓上述兩個(gè)定時(shí)器的實(shí)際執(zhí)行變得稍微復(fù)雜了一些。下面我們來看一下兩者的運(yùn)行機(jī)制與需要注意的問題。 基本原理 知識(shí)鋪墊 單線
    的頭像 發(fā)表于 09-19 15:10 ?1255次閱讀
    <b class='flag-5'>js</b>基礎(chǔ)之setTimeout與setInterval原理分析

    功放和運(yùn)放到底是什么區(qū)別?

    想請(qǐng)問一下功放和運(yùn)放到底是什么區(qū)別,感覺只要接一個(gè)小負(fù)載,運(yùn)放的輸出電流可以很大???到底有什么區(qū)別啊
    發(fā)表于 09-10 07:00

    運(yùn)放的輸入電容到底是什么?

    我想請(qǐng)問一下運(yùn)放的輸入電容到底是什么?
    發(fā)表于 09-04 06:52

    鴻蒙開發(fā):【線程模型】

    管理其他線程的ArkTS引擎實(shí)例,例如使用TaskPool(任務(wù)池)創(chuàng)建任務(wù)或取消任務(wù)、啟動(dòng)和終止Worker線程
    的頭像 發(fā)表于 06-13 16:38 ?411次閱讀
    鴻蒙<b class='flag-5'>開發(fā)</b>:【<b class='flag-5'>線程</b>模型】

    鴻蒙實(shí)戰(zhàn)開發(fā)-如何安全和高效的使用N-API開發(fā)Native模塊

    語言調(diào)用開銷、異步操作和線程安全四個(gè)角度出發(fā),給出安全、高效的 N-API 開發(fā)指導(dǎo)。 對(duì)象生命周期管理 在進(jìn)行 N-API 調(diào)用時(shí),引擎堆中對(duì)象的句柄 handle 會(huì)作為 napi_value 返回
    發(fā)表于 05-09 15:55

    Linux性能基準(zhǔn)測(cè)試工具選擇與測(cè)試策略

    Super_Pi 是一種用于計(jì)算圓周率π的程序,通常用于測(cè)試計(jì)算機(jī)性能和穩(wěn)定性。它的主要用途是測(cè)量系統(tǒng)的單線程性能,因?yàn)樗且粋€(gè)單線程應(yīng)用程序。
    發(fā)表于 04-26 16:24 ?396次閱讀
    Linux性能基準(zhǔn)測(cè)試工具選擇與測(cè)試策略

    鴻蒙OS開發(fā)實(shí)例:【ArkTS類庫異步并發(fā)簡(jiǎn)述Promise】

    Promise和async/await提供異步并發(fā)能力,是標(biāo)準(zhǔn)的JS異步語法。異步代碼會(huì)被掛起并在之后繼續(xù)執(zhí)行,同一時(shí)間只有一段代碼執(zhí)行,適用于單次I/O
    的頭像 發(fā)表于 04-02 18:37 ?978次閱讀
    鴻蒙OS<b class='flag-5'>開發(fā)</b>實(shí)例:【ArkTS類庫<b class='flag-5'>異步</b>并發(fā)簡(jiǎn)述Promise】

    鴻蒙OS開發(fā)實(shí)例:【ArkTS類庫多線程I/O密集型任務(wù)開發(fā)

    使用異步并發(fā)可以解決單次I/O任務(wù)阻塞的問題,但是如果遇到I/O密集型任務(wù),同樣會(huì)阻塞線程中其它任務(wù)的執(zhí)行,這時(shí)需要使用多
    的頭像 發(fā)表于 04-01 16:32 ?521次閱讀
    鴻蒙OS<b class='flag-5'>開發(fā)</b>實(shí)例:【ArkTS類庫多<b class='flag-5'>線程</b>I/O密集型<b class='flag-5'>任務(wù)</b><b class='flag-5'>開發(fā)</b>】

    鴻蒙原生應(yīng)用開發(fā)-ArkTS語言基礎(chǔ)類庫多線程I/O密集型任務(wù)開發(fā)

    使用異步并發(fā)可以解決單次I/O任務(wù)阻塞的問題,但是如果遇到I/O密集型任務(wù),同樣會(huì)阻塞線程中其它任務(wù)的執(zhí)行,這時(shí)需要使用多
    發(fā)表于 03-21 14:57

    共享單車到底是什么通信原理?

    我們經(jīng)常騎的共享單車到底是什么通信原理,有人了解過嗎?下面寶藍(lán)小編就帶大家了解下。
    的頭像 發(fā)表于 02-25 10:32 ?1418次閱讀
    共享單車<b class='flag-5'>到底是</b>什么通信原理?

    什么是多核多線程?多核多線程如何提高程序的運(yùn)行效率?

    單線程無法充分利用多核處理器的并行計(jì)算能力。
    的頭像 發(fā)表于 02-20 10:22 ?1366次閱讀

    HarmonyOS如何使用異步并發(fā)能力進(jìn)行開發(fā)

    一、并發(fā)概述 并發(fā)是指在同一時(shí)間段內(nèi),能夠處理多個(gè)任務(wù)的能力。為了提升應(yīng)用的響應(yīng)速度與幀率,以及防止耗時(shí)任務(wù)對(duì)主線程的干擾,HarmonyOS系統(tǒng)提供了異步并發(fā)和多
    的頭像 發(fā)表于 02-18 09:18 ?534次閱讀

    鴻蒙OS 線程管理開發(fā)指導(dǎo)

    場(chǎng)景介紹 如果應(yīng)用的業(yè)務(wù)邏輯比較復(fù)雜,可能需要?jiǎng)?chuàng)建多個(gè)線程來執(zhí)行多個(gè)任務(wù)。這種情況下,代碼復(fù)雜難以維護(hù),任務(wù)線程的交互會(huì)更加繁雜。要解決
    的頭像 發(fā)表于 01-29 16:22 ?844次閱讀

    Redis7單線程與多線程詳解

    主要是指Redis的網(wǎng)絡(luò)IO和鍵值對(duì)讀寫是由一個(gè)線程來完成的。
    的頭像 發(fā)表于 01-16 17:33 ?1854次閱讀
    Redis7<b class='flag-5'>單線程</b>與多<b class='flag-5'>線程</b>詳解