1.《Android Runtime源码解析》介绍
2.vue runtime源码分析学习——day4:createApp
3.如何实现定时任务- Java Timer/TimerTask 源码解析
4.如何编译 dotnet/runtime 源代码
5.用C语言做数字时钟每走一秒响一次,源码求大神告诉源代码
《Android Runtime源码解析》介绍
《Android Runtime源码解析》是源码我创作的第二本技术专著,于6月底完成印刷,源码现已在各大电商平台上市。源码借此机会,源码我简要介绍本书内容,源码文件下载主页源码以便对此感兴趣的源码朋友能有所了解。
本书以Android .0.0_r源码为基础,源码从编译器开发者的源码视角,分析了ART的源码各个部分及其主要流程,旨在向读者展示ART的源码基本框架。由于ART发展至今,源码规模庞大,源码复杂度较高,源码很多细节无法完全覆盖。源码因此,本书选择基本框架进行介绍,以便读者根据个人兴趣深入挖掘感兴趣的细节。
全书内容分为四个部分。第一部分包括第一章,同花顺趋势先锋指标源码主要介绍ART的基础知识;第二部分包括第二章至第四章,主要介绍ART中的编译器部分,包括dex2oat工具,这部分属于编译时阶段;第三部分包括第五章和第六章,主要介绍ART的启动和运行,属于运行时阶段;第四部分包括第七章,主要介绍ART中的垃圾回收部分。读者可以按照顺序阅读,也可以根据自己的需要选择阅读相关部分,不影响对内容的理解。
各章内容如下:第一章,从虚拟机基础、ART发展历史、ART核心架构和源码目录结构等方面对ART基础进行了介绍;第二章,介绍了dex2oat工具的入口、driver以及DexToDexCompiler等;第三章,分析了OptimizingCompiler中的JNI处理和Compile过程,并对Compile过程中的主要环节进行了详细阐述;第四章,介绍了OptimizingCompiler中硬件平台无关和硬件平台相关的风语5.0鲨鱼源码优化,并深入分析了硬件平台无关优化中的典型优化;第五章,分析了ART在启动时的几个主要流程;第六章,分析了ART在执行时的主要流程;第七章,分析了ART GC的整体架构、种类及具体实现。
本书适合新入行的ART开发者以及想了解ART基本情况的各类开发者。
由于作者水平有限,本书中可能存在诸多问题,敬请各位专家批评指正。
vue runtime源码分析学习——day4:createApp
在深入研究vue runtime源码时,我们首先确定了分析的路径和方法。
createApp这个关键入口点位于@vue/runtime-dom包中,它是开发者项目启动的起点。
在开始代码分析前,我们选择在packages\vue\__tests__\index.spec.ts中的测试用例进行,通常选择第一个即可,因为这里模拟的是客户端环境,但需确保testEvironment配置正确并配合jsdom库使用。
createApp方法内部包含一些开发环境特有的仿爱艺奇源码检查,如injectCompilerOptionsCheck和injectNativeTagCheck,它们在生产环境不会执行。通过Object.defineProperty绑定,可以防止这些检查被意外修改。
createApp的主要任务包括调用ensureRenderer、createAppApi和mount等。其中,ensureRenderer涉及到typescript的重载,而createAppApi则是通过缓存render和hydrate方法,优化性能。
在render部分,我们首次遇到reload,这是与vue-loader中热更新功能的联系点。尽管loader中的reload方法不接受参数,但它们本质上是处理相同逻辑的。
mount方法的核心内容是将js代码转化为DOM,它会处理createVNode和vnode的生成,以及与container._vnode的更新和比对,即旧vnode与新vnode的盲盒vue源码下载差异处理。
虽然今天的内容可能略显琐碎,但createApp的总体流程已经清晰了。后续将继续深入解析其他关键部分。
如何实现定时任务- Java Timer/TimerTask 源码解析
日常实现各种服务端系统时,我们一定会有一些定时任务的需求。比如会议提前半小时自动提醒,异步任务定时/周期执行等。那么如何去实现这样的一个定时任务系统呢? Java JDK提供的Timer类就是一个很好的工具,通过简单的API调用,我们就可以实现定时任务。
现在就来看一下java.util.Timer是如何实现这样的定时功能的。
首先,我们来看一下一个使用demo
基本的使用方法:
加入任务的API如下:
可以看到API方法内部都是调用sched方法,其中time参数下一次任务执行时间点,是通过计算得到。period参数为0的话则表示为一次性任务。
那么我们来看一下Timer内部是如何实现调度的。
内部结构
先看一下Timer的组成部分:
Timer有3个重要的模块,分别是 TimerTask, TaskQueue, TimerThread
那么,在加入任务之后,整个Timer是怎么样运行的呢?可以看下面的示意图:
图中所示是简化的逻辑,多个任务加入到TaskQueue中,会自动排序,队首任务一定是当前执行时间最早的任务。TimerThread会有一个一直执行的循环,从TaskQueue取队首任务,判断当前时间是否已经到了任务执行时间点,如果是则执行任务。
工作线程
流程中加了一些锁,用来避免同时加入TimerTask的并发问题。可以看到sched方法的逻辑比较简单,task赋值之后入队,队列会自动按照nextExecutionTime排序(升序,排序的实现原理后面会提到)。
从mainLoop的源码中可以看出,基本的流程如下所示
当发现是周期任务时,会计算下一次任务执行的时间,这个时候有两种计算方式,即前面API中的
优先队列
当从队列中移除任务,或者是修改任务执行时间之后,队列会自动排序。始终保持执行时间最早的任务在队首。 那么这是如何实现的呢?
看一下TaskQueue的源码就清楚了
可以看到其实TaskQueue内部就是基于数组实现了一个最小堆 (balanced binary heap), 堆中元素根据 执行时间nextExecutionTime排序,执行时间最早的任务始终会排在堆顶。这样工作线程每次检查的任务就是当前最早需要执行的任务。堆的初始大小为,有简单的倍增扩容机制。
TimerTask 任务有四种状态:
Timer 还提供了cancel和purge方法
常见应用
Java的Timer广泛被用于实现异步任务系统,在一些开源项目中也很常见, 例如消息队列RocketMQ的 延时消息/消费重试 中的异步逻辑。
上面这段代码是RocketMQ的延时消息投递任务 ScheduleMessageService 的核心逻辑,就是使用了Timer实现的异步定时任务。
不管是实现简单的异步逻辑,还是构建复杂的任务系统,Java的Timer确实是一个方便实用,而且又稳定的工具类。从Timer的实现原理,我们也可以窥见定时系统的一个基础实现:线程循环 + 优先队列。这对于我们自己去设计相关的系统,也会有一定的启发。
如何编译 dotnet/runtime 源代码
编译 dotnet/runtime 源代码,首先需要环境准备,参考官方文档《在Windows上构建dotnet/runtime的要求》。我的机器仅提前安装了 Visual Studio ,确保按需自行安装。
初次尝试在命令行窗口进入代码所在目录,输入编译命令时,遇到的第一个问题是缺少 Python 3。安装 Python 3 后,发现新问题,下载文件任务中下载地址参数无法识别。查阅 dotnet/runtime 的 issue,找到解决方案,其中发帖者也是中国人,解答了这一疑惑。
为了找到编译过程中的所有错误,运行命令生成日志。使用“MSBuild Structured Log Viewer”打开日志文件,能够清晰地查看到具体的下载地址。按照日志中的提示,下载文件,复制到指定位置解压,成功解决了下载错误。随后,再次编译,直至提示编译成功。
然而,运行 dotnet/runtime 自带的测试用例时,发现找不到指定 dll,进一步发现对应的 dll 已经编译,但默认编译的是 net7.0-Debug 版本,而需要的是 net-Debug。通过使用 build.cmd -h 查看,发现可以指定编译框架版本。因此,再次编译,指定正确的框架版本,最终运行测试成功。
总结,编译 dotnet/runtime 源代码过程中遇到的主要问题,主要是由于访问国外的网速较慢导致的下载问题。通过生成日志、使用“MSBuild Structured Log Viewer”查看下载地址,以及正确指定编译框架版本等方法,成功解决了编译和运行过程中遇到的问题。
用C语言做数字时钟每走一秒响一次,求大神告诉源代码
“响一次”需要牵涉到图形编程中的音乐播放问题,需要自己下载图形编程相关库文件,具体实现请自己在TODO里添加播放音乐的代码数字时钟的实现很简单,运用time.h相关函数即可
#include<stdio.h>#include<stdlib.h>
#include<time.h>
time_t oldt=-1;
struct tm *p;
bool Printdate()
{
time_t t=time(NULL);
if(t!=oldt)
{
oldt=t;
p=localtime(&t);
system("cls");
printf("%d/%d/%d 周",+p->tm_year,1+p->tm_mon,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
switch(p->tm_wday)
{
case 1:printf("一");break;
case 2:printf("二");break;
case 3:printf("三");break;
case 4:printf("四");break;
case 5:printf("五");break;
case 6:printf("六");break;
case 7:printf("日");break;
}
printf(" %d:%d:%d ", p->tm_hour, p->tm_min, p->tm_sec);
return 1;
}
return 0;
}
main()
{
while(1)
if(Printdate())
{
/