引子

GitHub 上有许多优异的开源项目,代码都是通明可见的,每个人只要有账号就能够下载来查看。而咱们作为软件开发者来说也能够从中学习到许多知识,以及领会如何正确的工程化、单元测试、一致代码风格等,乃至从源码中找到问题,并提出 Pull Request 来奉献开源社区。今日这篇文章将解析 Go 言语开源项目 robfig/cron 的源码,这个项目不大,知名度较高,注释也比较清楚,很适合新手学习如何阅览和解析源码。

环境预备

首要咱们将源码克隆(Fork)为自己的个人库房,只需求在 GitHub 项目主页点击 Fork 按钮,然后输入项目称号点击确认即可。克隆完毕后,能够下载到本地,或许直接在科隆后的 GitHub 库房主页上点击 Create codespace on master 来创立 Codespace。Codespace 是 GitHub 推出的基于 Azure 云服务的远程编程功用,现在对个人账号开放了,能够试一下。

Go 语言项目源码解析:定时任务库 cron

点击后,浏览器中会翻开一个新页面,并会呈现在线 VS Code 的界面,然后显现该项目的目录、代码以及终端,如下图。

Go 语言项目源码解析:定时任务库 cron

由于咱们本次的目的是解析源码,咱们首要将在这上面展现和阅览代码,并不会履行它。

现在,咱们能够开端解析源码了。

进口文件

解析源码的一个比较好的手法是找到进口文件(Entry File),适当于是一本书的导言(Introduction)章节,项目的全体结构一般会在进口文件中体现出来。

Go 语言项目源码解析:定时任务库 cron

咱们从项目介绍 README.md 文件中能够看到,这个守时使命库的使用办法是 cron.New(cron.WithSeconds()) 之类的,也便是 cron.New 办法。因而,咱们能够猜想这个办法是在 cron.go 中,咱们翻开它看一看。

快速扫了一遍之后,咱们能够发现这个 New 办法在 113 行,如下图。

Go 语言项目源码解析:定时任务库 cron

仔细看一下,这个办法便是回来了一个 Cron 类的实例指针,中心的 opts ...Option 参数是一种函数式参数(Functional Option)。而实际的代码实现,无非便是结构了一个 Cron 类的实例指针 c,并对其应用了函数参数,然后回来它。

这样,咱们能够判别,真实的守时使命中心逻辑就在 Cron 类中。

不过,无论如何,咱们能够确认,进口文件便是 cron.go。接下来只需求剖析这个文件包含的中心模块、逻辑就能够大概理清楚整个项目的源码了。

中心类

那么咱们再来看一下中心类 Cron 的结构,看看是否有什么新东西。

在代码中查找一下能够定位到 Cron 类在第 13 行。

Go 语言项目源码解析:定时任务库 cron

Cron 类有许多特点,包含小写单词表明的私有特点 entrieschainparser 等等,咱们暂时还不知道它们各自的意义,不过能够从称号猜想一下。别的,咱们还能够看到第 10-12 行的注释描绘,意思是 Cron 会追寻 entries,并履行被 schedule 界说的函数,它能够开端运转、完毕运转,以及 entries 也会在运转进程中被查看。一脸懵逼?是的,这些描绘尽管长,但并不能完全解说清楚,咱们只要持续阅览更多源码中的细节,才干够了解清楚。

别的,咱们还能够在 Cron 类下面发现 3 个接口以及其描绘:

  • ScheduleParser:守时使命的解析器,能够解析并回来 Schedule 实例;
  • Job:已提交的守时使命作业
  • Schedule:用于描绘作业的运转周期。

其实,这 3 个接口都很重要,咱们从它们的所在位置就能够判别出来。

进口办法

在持续探索之前,咱们再回想一下这个守时使命库的使用办法,除了 cron.New 之外,还需求调用 c.Start() 才干正式收效。因而,咱们需求仔细看看 Cron 类的 Start 办法。这其实也是中心类的进口办法(Entry Method)。

咱们能够在 cron.go 文件中定位到 Start 办法在第 215 行,如下图。

Go 语言项目源码解析:定时任务库 cron

比较有经历的 Go 言语开发工程师应该会注意到,这是一个典型的原子性操作(Atomic Operation)。c.runningMu 是一个 sync.Mutex 实例,能够加锁(Lock);然后 defer c.runningMu.Unlock() 表明函数调用之后会解锁(Unlock),因而保证重复调用该办法的时分不会呈现数据竞速(Data Race);if c.running { return } 的办法表明,如果现已开端运转了,就不会再履行,直接回来;c.running 设置运转状况为 true;最终一行比较要害,go c.run() 表明新起了一个协程(Goroutine)来运转 c.run 办法。因而,咱们找到了更中心的办法,run。接下来的作业便是持续解析它了。

是不是很像玩 RPG 游戏时不断寻找机关,最终在含辛茹苦之下可喜可贺进入下一关?

总结

等一下,就这么结束撒花了?我那啥都预备好了,你就让我看这个?

咱们在这里暂时打住的首要原因是不想让这篇文章变得又臭又长。由于源码解析一般是一个需求耐性繁琐单调的进程,而这种进程有时会让读者产生抵触情绪。因而,笔者的首要目的是抛砖引玉,将源码解析的一些中心方法用手把手的办法告诉读者,而读者也会根据自己的理解去实际操作,这样学习起来会更快也会更有意思。

现在稍微总结一下这篇文章用到的解析源码技巧:

  1. 找到进口文件
  2. 定位中心类
  3. 解析进口办法

社区

如果您对笔者的文章感兴趣,能够加笔者微信 tikazyq1 并注明 “码之道”,笔者会将你拉入 “码之道” 交流群。