乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      讀了鴻蒙 OS 的代碼后,我發(fā)現(xiàn)優(yōu)秀項目都有這個共性!

       liang1234_ 2019-08-30

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

      兩個項目對于任務(wù)調(diào)度模塊的實現(xiàn)對比

      1.鴻蒙OS的調(diào)度模塊
      與一般操作系統(tǒng)一樣,鴻蒙也將任務(wù)狀態(tài)通常分為以下三種:
      • 就緒(Ready):

        該任務(wù)在就緒列表中,只等待CPU。

      • 運行(Running):

        該任務(wù)正在執(zhí)行。

      • 阻塞(Blocked):

        該任務(wù)不在就緒列表中。

        包含任務(wù)被掛起、任務(wù)被延時、任務(wù)正在等待信號量、讀寫隊列或者等待讀寫事件等。

      任務(wù)狀態(tài)遷移圖
      其代碼位置在los_task.c,以任務(wù)恢復(fù)函數(shù)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();
          }
          //以上為任務(wù)狀態(tài)檢查
          pstTaskCB->usTaskStatus &= (~OS_TASK_STATUS_SUSPEND);//清除任務(wù)的suspend標(biāo)志位置
          if (!(OS_CHECK_TASK_BLOCK & pstTaskCB->usTaskStatus) )//若任務(wù)的還自在阻塞狀態(tài)則變?yōu)榫途w狀態(tài) ,并調(diào)用 LOS_Schedule()進(jìn)行調(diào)度
          {
              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;
      }
       我們看到這個函數(shù)的處理過程基本分為三步:
      • 任務(wù)合法性(TaskId)及任務(wù)狀態(tài)校驗:判斷任務(wù)序號以及任務(wù)當(dāng)前狀態(tài)是否確實為掛起。

      • 改變?nèi)蝿?wù)狀態(tài):將任務(wù)的suspend狀態(tài)位清掉

      • 起用任務(wù)調(diào)度:如果任務(wù)被阻塞,則調(diào)起LOS_Schedule進(jìn)行調(diào)度。

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

      • 加入任務(wù)

      • 循環(huán)處理任務(wù)

      • 銷毀任務(wù)隊列

      從其循環(huán)處理任務(wù)的函數(shù)(taosProcessSchedQueue),可以看出它只是隊尾不斷取出任務(wù)進(jìn)行循環(huán)處理,而沒有優(yōu)化級調(diào)整排序的過程。
      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
      ', pSched->label, strerror(errno));

          if (sem_post(&pSched->emptySem) != 0)
            pError('post %s emptySem failed, reason:%s
      ', 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)的實現(xiàn)對比

      1.鴻蒙的timer
      在鴻蒙的官方文檔中是這么介紹定時器的:
      軟件定時器,是基于系統(tǒng)Tick時鐘中斷且由軟件來模擬的定時器,當(dāng)經(jīng)過設(shè)定的Tick時鐘計數(shù)值后會觸發(fā)用戶定義的回調(diào)函數(shù)。定時精度與系統(tǒng)Tick時鐘的周期有關(guān)。 
      硬件定時器受硬件的限制,數(shù)量上不足以滿足用戶的實際需求,因此為了滿足用戶需求,提供更多的定時器,Huawei LiteOS操作系統(tǒng)提供軟件定時器功能。軟件定時器擴(kuò)展了定時器的數(shù)量,允許創(chuàng)建更多的定時業(yè)務(wù)。
      2.運作機(jī)制
      • 軟件定時器是系統(tǒng)資源,在模塊初始化的時候已經(jīng)分配了一塊連續(xù)的內(nèi)存,系統(tǒng)支持的最大定時器個數(shù)可以在los_config.h文件中配置。

      • 軟件定時器使用了系統(tǒng)的一個隊列和任務(wù)資源,軟件定時器的觸發(fā)遵循隊列規(guī)則,先進(jìn)先出。

        定時時間短的定時器總是比定時時間長的靠近隊列頭,滿足優(yōu)先被觸發(fā)的準(zhǔn)則。

      • 軟件定時器以Tick為基本計時單位,當(dāng)用戶創(chuàng)建并啟動一個軟件定時器時,Huawei LiteOS會根據(jù)當(dāng)前系統(tǒng)Tick時間及用戶設(shè)置的定時間隔確定該定時器的到期Tick時間,并將該定時器控制結(jié)構(gòu)掛入計時全局鏈表。

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

      • Tick處理結(jié)束后,軟件定時器任務(wù)(優(yōu)先級為最高)被喚醒,在該任務(wù)中調(diào)用之前記錄下來的超時定時器的處理函數(shù)。

      3.代碼解讀
      如果官方文檔的說明沒看懂,可以直接查閱其源代碼,具體位置在los_swtmr.c
      下面筆者來簡述一下鴻蒙定時器的工作原理。
      • 首先明確鴻蒙的定時器是為了節(jié)省硬件定時器資源而設(shè)計的。

        由于硬件定時器往往數(shù)量有限而系統(tǒng)實際運行中,對于定時器的需求往往高于硬件定時器的數(shù)量,所以操作系統(tǒng)都會實現(xiàn)軟件定時器以滿足用戶需求。

      • 先啟動硬件定時器,注冊硬件定時器的tick事件,也就是硬件定時器到時發(fā)生tick時會調(diào)用軟件定時器的處理函數(shù)。

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

      • 在硬件產(chǎn)生tick事件時,取出當(dāng)時到期的定時器列表,并順序調(diào)起鏈表內(nèi)所有到時定時器的處理函數(shù)。

      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
      }

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

      4.timer之間的對比
      其實Tdengine的timer我之前已經(jīng)做過解讀了,200行代碼為大家解讀這個Github冠軍項目背后的定時器。就不加贅述了,這里把鴻蒙和Tdengine的timer做一下簡單的對比:
      節(jié)約關(guān)鍵資源:由于每個操作系統(tǒng)的timer都需要一個線程進(jìn)行回調(diào)處理,這對于Tdengine這種數(shù)據(jù)庫動轍幾萬個timer的應(yīng)用來說是不可接受的,所以為了節(jié)省線程資源,Td要用自己實現(xiàn)的timer之所以要實現(xiàn)自己的定時器是為了節(jié)省線程資源。而鴻蒙實現(xiàn)timer則是為了節(jié)約硬件定時器資源。
      最簡化設(shè)計:兩個timer都沒有優(yōu)先級的設(shè)定。其中鴻蒙OS做為移動操作系統(tǒng)直接將timer的精度值也舍棄了。
      使用雙鏈表提高效率:兩個timer都使用雙鏈表來存儲同一時刻到期的定時器,這樣能節(jié)省遍歷和移動的時間,大大提高效率。

      結(jié)語

      從上面這兩個簡單的模塊中我們也看到這些優(yōu)秀的項目都使用最精簡的設(shè)計,緊貼需求、甩掉包袱、輕裝上陣才能回歸本質(zhì)取得成功。
      無論是TdEngine取消任務(wù)調(diào)度的優(yōu)先級排序,還是鴻蒙放棄對定時器精度的支持,都是看來出乎意料,實則頗具內(nèi)涵的減法操作。真正優(yōu)秀的項目都是敢于做減法的,只有減掉那些看似高大上的設(shè)計,才能向著有取有舍,大道至簡的境界邁進(jìn)。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多