日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

读了鸿蒙 OS 的代码后,我发现优秀项目都有这个共性!

發布時間:2025/3/16 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 读了鸿蒙 OS 的代码后,我发现优秀项目都有这个共性! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 馬超

責編 | 胡巍巍

出品 | 程序人生(ID:coder_life)


最近有人在Github上開源了鴻蒙OS(https://www.github.com/Awesome-HarmonyOS)并且累計獲得了一萬多顆Star。從華為的官方宣傳中就提到了“安卓總代碼超過一億行,其中內核代碼超過2000萬行,實際用到的不過8%,如此龐大和冗余的這種設計,實際上很難保證流暢度,使用效率很低。”?而筆者之前介紹過的TDengine(https://github.com/taosdata/TDengine)做為一個數據庫項目更是僅用1.5M安裝包就能搞定,代碼效率高的驚人。所以從這方面我們也能看出優秀的項目對于速度的要求都是極致的。不過這兩個項目開源后都引發了一些爭議,比如鴻蒙開源當天就有人發微博說華為只是做了個安卓的定制版,質量甚至還不如MIUI,筆者的這位創造Github冠軍項目的老男人,堪稱10倍程序員本尊發布后,也有人在評論說TDengine的consumer-productor實現無法通過code review。但是仔細閱讀這些評論可以發現,這些批評其實都不是基于代碼的。筆者做為一名程序員奉行“Talk is cheap,show me the code"的理念,所以我利用周末時間閱讀了這兩個項目的代碼,發現了很多值得學習的設計亮點。尤其是鴻蒙OS做為操作系統項目而Tdengine做為數據庫項目,比較他們兩者在同一模塊上的設計異同,非常有收獲,下面給各位讀者分享一下,如有意見歡迎留言。
兩個項目對于任務調度模塊的實現對比1.鴻蒙OS的調度模塊與一般操作系統一樣,鴻蒙也將任務狀態通常分為以下三種:


  • 就緒(Ready):該任務在就緒列表中,只等待CPU。

  • 運行(Running):該任務正在執行。

  • 阻塞(Blocked):該任務不在就緒列表中。包含任務被掛起、任務被延時、任務正在等待信號量、讀寫隊列或者等待讀寫事件等。




任務狀態遷移圖其代碼位置在los_task.c,以任務恢復函數LOS_TaskResume為例,其代碼如下:LITE_OS_SEC_TEXT_INIT?UINT32?LOS_TaskResume(UINT32?uwTaskID)
{
????UINTPTR?uvIntSave;
????LOS_TASK_CB?*pstTaskCB;
????UINT16?usTempStatus;
????UINT32?uwErrRet?=?OS_ERROR;

????if?(uwTaskID?>?LOSCFG_BASE_CORE_TSK_LIMIT)
????{
????????return?LOS_ERRNO_TSK_ID_INVALID;
????}

????pstTaskCB?=?OS_TCB_FROM_TID(uwTaskID);
????uvIntSave?=?LOS_IntLock();
????usTempStatus?=?pstTaskCB->usTaskStatus;

????if?(OS_TASK_STATUS_UNUSED?&?usTempStatus)
????{
????????uwErrRet?=?LOS_ERRNO_TSK_NOT_CREATED;
????????OS_GOTO_ERREND();
????}
????else?if?(!(OS_TASK_STATUS_SUSPEND?&?usTempStatus))
????{
????????uwErrRet?=?LOS_ERRNO_TSK_NOT_SUSPENDED;
????????OS_GOTO_ERREND();
????}
????//以上為任務狀態檢查
????pstTaskCB->usTaskStatus?&=?(~OS_TASK_STATUS_SUSPEND);//清除任務的suspend標志位置
????if?(!(OS_CHECK_TASK_BLOCK?&?pstTaskCB->usTaskStatus)?)//若任務的還自在阻塞狀態則變為就緒狀態?,并調用?LOS_Schedule()進行調度
????{
????????pstTaskCB->usTaskStatus?|=?OS_TASK_STATUS_READY;
????????LOS_PriqueueEnqueue(&pstTaskCB->stPendList,?pstTaskCB->usPriority);
????????if?(g_bTaskScheduled)
????????{
????????????(VOID)LOS_IntRestore(uvIntSave);
????????????LOS_Schedule();
????????????return?LOS_OK;
????????}
????????g_stLosTask.pstNewTask?=?LOS_DL_LIST_ENTRY(LOS_PriqueueTop(),?LOS_TASK_CB,?stPendList);?/*lint?!e413*/
????}

????(VOID)LOS_IntRestore(uvIntSave);
????return?LOS_OK;

LOS_ERREND:
????(VOID)LOS_IntRestore(uvIntSave);
????return?uwErrRet;
}
我們看到這個函數的處理過程基本分為三步:


  • 任務合法性(TaskId)及任務狀態校驗:判斷任務序號以及任務當前狀態是否確實為掛起。

  • 改變任務狀態:將任務的suspend狀態位清掉

  • 起用任務調度:如果任務被阻塞,則調起LOS_Schedule進行調度。


我們知道完整的LINUX內核是支持將任務指定在某個CPU上運行的,不過鴻蒙OS做為一個微內核的移動操作系統沒有繼承這些復雜的功能,直接做了減法,實現一個最簡模型。2.TdEngine的任務調度模塊? ?而對比TDengine的調度模塊tsched.c,可以看到TDengine更是放棄了任務優先級調度功能,因為做為時序數據庫其數據全是按照生成時間排序處理入庫的,所以他的只將任務調度模塊,僅實現了以下四個功能
  • 初始化任務隊列

  • 加入任務

  • 循環處理任務

  • 銷毀任務隊列

從其循環處理任務的函數(taosProcessSchedQueue),可以看出它只是隊尾不斷取出任務進行循環處理,而沒有優化級調整排序的過程。void?*taosProcessSchedQueue(void?*param)?{
??SSchedMsg????msg;
??SSchedQueue?*pSched?=?(SSchedQueue?*)param;

??while?(1)?{
????if?(sem_wait(&pSched->fullSem)?!=?0)?{
??????pError("wait?%s?fullSem?failed,?errno:%d,?reason:%s",?pSched->label,?errno,?strerror(errno));
??????if?(errno?==?EINTR)?{
????????/*?sem_wait?is?interrupted?by?interrupt,?ignore?and?continue?*/
????????continue;
??????}
????}

????if?(pthread_mutex_lock(&pSched->queueMutex)?!=?0)
??????pError("lock?%s?queueMutex?failed,?reason:%s",?pSched->label,?strerror(errno));

????msg?=?pSched->queue[pSched->fullSlot];
????memset(pSched->queue?+?pSched->fullSlot,?0,?sizeof(SSchedMsg));
????pSched->fullSlot?=?(pSched->fullSlot?+?1)?%?pSched->queueSize;//從隊尾取出消息不斷處理

????if?(pthread_mutex_unlock(&pSched->queueMutex)?!=?0)
??????pError("unlock?%s?queueMutex?failed,?reason:%s\n",?pSched->label,?strerror(errno));

????if?(sem_post(&pSched->emptySem)?!=?0)
??????pError("post?%s?emptySem?failed,?reason:%s\n",?pSched->label,?strerror(errno));

????if?(msg.fp)
??????(*(msg.fp))(&msg);
????else?if?(msg.tfp)
??????(*(msg.tfp))(msg.ahandle,?msg.thandle);
??}
}

int?taosScheduleTask(void?*qhandle,?SSchedMsg?*pMsg)?{
??SSchedQueue?*pSched?=?(SSchedQueue?*)qhandle;
??if?(pSched?==?NULL)?{
????pError("sched?is?not?ready,?msg:%p?is?dropped",?pMsg);
????return?0;
??}

??if?(sem_wait(&pSched->emptySem)?!=?0)?pError("wait?%s?emptySem?failed,?reason:%s",?pSched->label,?strerror(errno));

??if?(pthread_mutex_lock(&pSched->queueMutex)?!=?0)
????pError("lock?%s?queueMutex?failed,?reason:%s",?pSched->label,?strerror(errno));

??pSched->queue[pSched->emptySlot]?=?*pMsg;
??pSched->emptySlot?=?(pSched->emptySlot?+?1)?%?pSched->queueSize;

??if?(pthread_mutex_unlock(&pSched->queueMutex)?!=?0)
????pError("unlock?%s?queueMutex?failed,?reason:%s",?pSched->label,?strerror(errno));

??if?(sem_post(&pSched->fullSem)?!=?0)?pError("post?%s?fullSem?failed,?reason:%s",?pSched->label,?strerror(errno));

??return?0;
}


??? 兩個項目對于定時器(timer)的實現對比1.鴻蒙的timer在鴻蒙的官方文檔中是這么介紹定時器的:軟件定時器,是基于系統Tick時鐘中斷且由軟件來模擬的定時器,當經過設定的Tick時鐘計數值后會觸發用戶定義的回調函數。定時精度與系統Tick時鐘的周期有關。硬件定時器受硬件的限制,數量上不足以滿足用戶的實際需求,因此為了滿足用戶需求,提供更多的定時器,Huawei LiteOS操作系統提供軟件定時器功能。軟件定時器擴展了定時器的數量,允許創建更多的定時業務。2.運作機制


  • 軟件定時器是系統資源,在模塊初始化的時候已經分配了一塊連續的內存,系統支持的最大定時器個數可以在los_config.h文件中配置。

  • 軟件定時器使用了系統的一個隊列和任務資源,軟件定時器的觸發遵循隊列規則,先進先出。

    定時時間短的定時器總是比定時時間長的靠近隊列頭,滿足優先被觸發的準則。

  • 軟件定時器以Tick為基本計時單位,當用戶創建并啟動一個軟件定時器時,Huawei LiteOS會根據當前系統Tick時間及用戶設置的定時間隔確定該定時器的到期Tick時間,并將該定時器控制結構掛入計時全局鏈表。

  • 當Tick中斷到來時,在Tick中斷處理函數中掃描軟件定時器的計時全局鏈表,看是否有定時器超時,若有則將超時的定時器記錄下來。

  • Tick處理結束后,軟件定時器任務(優先級為最高)被喚醒,在該任務中調用之前記錄下來的超時定時器的處理函數。


3.代碼解讀如果官方文檔的說明沒看懂,可以直接查閱其源代碼,具體位置在los_swtmr.c下面筆者來簡述一下鴻蒙定時器的工作原理。


  • 首先明確鴻蒙的定時器是為了節省硬件定時器資源而設計的。

    由于硬件定時器往往數量有限而系統實際運行中,對于定時器的需求往往高于硬件定時器的數量,所以操作系統都會實現軟件定時器以滿足用戶需求。

  • 先啟動硬件定時器,注冊硬件定時器的tick事件,也就是硬件定時器到時發生tick時會調用軟件定時器的處理函數。

  • 將在同一時刻到期的timer放在同一鏈表中。

  • 在硬件產生tick事件時,取出當時到期的定時器列表,并順序調起鏈表內所有到時定時器的處理函數。


LITE_OS_SEC_TEXT?VOID?osSwTmrTask(VOID)
{
????SWTMR_HANDLER_ITEM_P?pstSwtmrHandle?=?(SWTMR_HANDLER_ITEM_P)NULL;
????SWTMR_HANDLER_ITEM_S?stSwtmrHandle;
????UINT32?uwRet;

????for?(?;?;?)
????{
????????uwRet?=?LOS_QueueRead(m_uwSwTmrHandlerQueue,?&pstSwtmrHandle,?sizeof(SWTMR_HANDLER_ITEM_P),?LOS_WAIT_FOREVER);
????????if?(uwRet?==?LOS_OK)
????????{
????????????if?(pstSwtmrHandle?!=?NULL)
????????????{
????????????????stSwtmrHandle.pfnHandler?=?pstSwtmrHandle->pfnHandler;
????????????????stSwtmrHandle.uwArg?=?pstSwtmrHandle->uwArg;
????????????????(VOID)LOS_MemboxFree(m_aucSwTmrHandlerPool,?pstSwtmrHandle);
????????????????if?(stSwtmrHandle.pfnHandler?!=?NULL)
????????????????{
????????????????????stSwtmrHandle.pfnHandler(stSwtmrHandle.uwArg);
????????????????}
????????????}
????????}
????}//end?of?for
}


以上函數的運行原理動畫解析如下:


4.timer之間的對比其實Tdengine的timer我之前已經做過解讀了,200行代碼為大家解讀這個Github冠軍項目背后的定時器。就不加贅述了,這里把鴻蒙和Tdengine的timer做一下簡單的對比:節約關鍵資源:由于每個操作系統的timer都需要一個線程進行回調處理,這對于Tdengine這種數據庫動轍幾萬個timer的應用來說是不可接受的,所以為了節省線程資源,Td要用自己實現的timer之所以要實現自己的定時器是為了節省線程資源。而鴻蒙實現timer則是為了節約硬件定時器資源。最簡化設計:兩個timer都沒有優先級的設定。其中鴻蒙OS做為移動操作系統直接將timer的精度值也舍棄了。使用雙鏈表提高效率:兩個timer都使用雙鏈表來存儲同一時刻到期的定時器,這樣能節省遍歷和移動的時間,大大提高效率。
結語從上面這兩個簡單的模塊中我們也看到這些優秀的項目都使用最精簡的設計,緊貼需求、甩掉包袱、輕裝上陣才能回歸本質取得成功。無論是TdEngine取消任務調度的優先級排序,還是鴻蒙放棄對定時器精度的支持,都是看來出乎意料,實則頗具內涵的減法操作。真正優秀的項目都是敢于做減法的,只有減掉那些看似高大上的設計,才能向著有取有舍,大道至簡的境界邁進。原文:https://blog.csdn.net/BEYONDMA/article/details/100049796?utm_source=app

在 GitHub 更新中,歡迎關注,歡迎star。

直面Java第262期:volatile是如何解決有序性問題的?

深入并發第009期:到底什么是Java內存模型?

- MORE | 更多精彩文章 -


如果你喜歡本文,

請長按二維碼,關注?Hollis.

轉發至朋友圈,是對我最大的支持。


好文章,我在看??

總結

以上是生活随笔為你收集整理的读了鸿蒙 OS 的代码后,我发现优秀项目都有这个共性!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。