比较了鸿蒙LITEOS和Tdengine的底层代码后,我发现优秀项目都是做减法的
最近华为鸿蒙OS终于正式发布,通过比较华为鸿蒙OS与之前在Github上开源的(https://www.github.com/Awesome-HarmonyOS)鸿蒙liteOS代码,笔者发现他们在任务调度,定时器及mqtt几个模块与鸿蒙OS的介绍是完全一致的,基本可以确定这几个模块中liteOS的代码就是鸿蒙OS的代码,从反响上看国人对于华为是非常支持的,liteOS都累计获得了一万多颗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更是放弃了任务优先级调度功能,因为做为时序数据库其数据全是按照生成时间排序处理入库的,所以他的只将任务调度模块,仅实现了以下四个功能
1.初始化任务队列
2.加入任务
3.循环处理任务
4.销毁任务队列
从其循环处理任务的函数(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操作系统提供软件定时器功能。软件定时器扩展了定时器的数量,允许创建更多的定时业务。
运作机制
1.软件定时器是系统资源,在模块初始化的时候已经分配了一块连续的内存,系统支持的最大定时器个数可以在los_config.h文件中配置。
2.软件定时器使用了系统的一个队列和任务资源,软件定时器的触发遵循队列规则,先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。
3.软件定时器以Tick为基本计时单位,当用户创建并启动一个软件定时器时,Huawei LiteOS会根据当前系统Tick时间及用户设置的定时间隔确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。
3.当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。
3.Tick处理结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的超时定时器的处理函数。
代码解读
如果官方文档的说明没看懂,可以直接查阅其源代码,具体位置在los_swtmr.c
下面笔者来简述一下鸿蒙定时器的工作原理。
1.首先明确鸿蒙的定时器是为了节省硬件定时器资源而设计的。由于硬件定时器往往数量有限而系统实际运行中,对于定时器的需求往往高于硬件定时器的数量,所以操作系统都会实现软件定时器以满足用户需求。
2.先启动硬件定时器,注册硬件定时器的tick事件,也就是硬件定时器到时发生tick时会调用软件定时器的处理函数。
3.将在同一时刻到期的timer放在同一链表中。
4.在硬件产生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
}
以上函数的运行原理动画解析如下:
1.timer之间的对比
其实Tdengine的timer我之前已经做过解读了,200行代码为大家解读这个Github冠军项目背后的定时器。就不加赘述了,这里把鸿蒙和Tdengine的timer做一下简单的对比:
节约关键资源:由于每个操作系统的timer都需要一个线程进行回调处理,这对于Tdengine这种数据库动辙几万个timer的应用来说是不可接受的,所以为了节省线程资源,Td要用自己实现的timer之所以要实现自己的定时器是为了节省线程资源。而鸿蒙实现timer则是为了节约硬件定时器资源。
最简化设计:两个timer都没有优先级的设定。其中鸿蒙OS做为移动操作系统直接将timer的精度值也舍弃了。
使用双链表提高效率:两个timer都使用双链表来存储同一时刻到期的定时器,这样能节省遍历和移动的时间,大大提高效率。
结语
从上面这两个简单的模块中我们也看到这些优秀的项目都使用最精简的设计,紧贴需求、甩掉包袱、轻装上阵才能回归本质取得成功。无论是TdEngine取消任务调度的优先级排序,还是鸿蒙放弃对定时器精度的支持,都是看来出乎意料,实则颇具内涵的减法操作。真正优秀的项目都是敢于做减法的,只有减掉那些看似高大上的设计,才能向着有取有舍,大道至简的境界迈进。
比较了鸿蒙LITEOS和Tdengine的底层代码后,我发现优秀项目都是做减法的相关推荐
- 读了鸿蒙 OS 的代码后,我发现优秀项目都有这个共性!
作者 | 马超 责编 | 胡巍巍 出品 | 程序人生(ID:coder_life) 最近有人在Github上开源了鸿蒙OS(https://www.github.com/Awesome-Harmony ...
- 鸿蒙支持lOS,读了鸿蒙 OS 的代码后,我发现优秀项目都有这个共性!
最近有人在Github上开源了鸿蒙OS(https://www.github.com/Awesome-HarmonyOS)并且累计获得了一万多颗Star.从华为的官方宣传中就提到了"安卓总代 ...
- 鸿蒙os执行效率最高的是多少级,华为鸿蒙OS升级半个多月后,好评度虽高,但“差评”也很扎心!...
原标题:华为鸿蒙OS升级半个多月后,好评度虽高,但"差评"也很扎心! 中美科技竞争的不断升温,鸿蒙操作系统,成了华为面临"十面封锁"中的一道亮光,不仅能让华为在 ...
- 华为鸿蒙vivo,华为鸿蒙成功的关键:要让小米、OPPO、VIVO都用上鸿蒙
众所周知,这几天手机界最大的新闻,莫过于华为鸿蒙2.0正式发布,余承东表示12月开始用,明年所有华为手机全面启用鸿蒙的消息了. 毕竟一直以来,国内的手机都是使用国外的安卓,现在有了自己的系统,可以不用 ...
- 微软获GPT-3独家授权,可访问底层代码,Open AI:API用户可继续使用
杨净 发自 凹非寺 量子位 报道 | 公众号 QbitAI 微软今天宣布,获得OpenAI GPT-3的独家授权. 毕竟也是投资10亿美元的金主爸爸,这个结果并不意外. 虽然目前尚不清楚具体授权许可 ...
- 华为合作oppovivo小米鸿蒙,华为鸿蒙成功的关键:要让小米、OPPO、VIVO都用上鸿蒙...
众所周知,这几天手机界最大的新闻,莫过于华为鸿蒙2.0正式发布,余承东表示12月开始用,明年所有华为手机全面启用鸿蒙的消息了. 毕竟一直以来,国内的手机都是使用国外的安卓,现在有了自己的系统,可以不用 ...
- ML之FE:特征工程中常用的一些处理手段(缺失值填充、异常值检测等)及其对应的底层代码的实现
ML之FE:特征工程中常用的一些处理手段(缺失值填充.异常值检测等)及其对应的底层代码的实现 目录 特征工程中常用的一些处理手段(缺失值填充.异常值检测等)及其对应的底层代码的实现
- Interview:算法岗位面试—10.12上午—上海某科技公司图像算法岗位(偏图像算法,互联网AI行业)技术面试考点之LoR逻辑回归的底层代码实现、特征图计算公式
ML岗位面试:10.12上午-上海某科技公司图像算法岗位(偏图像算法,互联网AI行业)技术面试考点之LoR逻辑回归的底层代码实现.特征图计算公式 Interview:算法岗位面试-10.12上午-上海 ...
- 推出了底层代码chatbot开发工具,Rulai获650万美元融资
客户体验chatbot开发公司 Rulai 推出了底层代码 chatbot 开发工具,并获得了650万美元资金.Rulai 的开发团队在北京和加利福尼亚州坎贝尔设有办事处,开发团队由加利福尼亚大学圣克 ...
最新文章
- 神经网络:卷积神经网络CNN
- mysql优化的重要参数 key_buffer_size table_cache
- node.js 没有转发_如何用Nodejs编写一个定时消息提醒应用?
- activity 启动模式_Intent#FLAG_ACTIVITY_CLEAR_TOP 真的会 clear top 吗
- Oracle创建 表空间 用户 给用户授权命令
- 到底是谁发明了物联网?
- CADFANS2012网站源码
- 【记录】word 插入高亮代码
- 抢小米脚本 java,java写自动抢小米手机程序
- VMware vSphere下载
- 申克称重控制器维修称重仪表VEG20612/VDB20600
- 【渝粤题库】陕西师范大学200941小学数学教学论 作业(高起专)
- android 关闭第三方应用,Android禁用第三方应用
- snapchat 登录不上_如何在Snapchat上阻止某人
- 【你问我答】不包装简历是不是面试机会都没有?
- 高盐废水处理工艺——料液精制与除杂
- python 的math函数库
- 我爱我妻——可以让男人看一遍哭一遍的文章!
- python随机爬取wallhaven壁纸url(获取随机图片url)
- jmeter 的基本使用