这篇文章中提到了 tsched 的源码可以一读,所以去阅读了一下,总共220来行。

1. 阅读前工作

通过上文了解到这段程序实现的是一个任务队列,同时带有线程池。这段程序是计算机操作系统里经典的consumer-producer (生产者-消费者)问题的实现。凡是学过操作系统这门课的,都应该知道这个问题,做过习题。在阅读源码之前可以先尝试用伪代码实现上述生产者-消费者问题。

2. 如何阅读?

了解清楚使用场景

这是一个线程池,客户端可以提交任务,线程池按照顺序调度执行任务。通过阅读 tsched.h 头文件,知道主要有三个函数:

  1. 初始化命名的调度器、线程池:taosInitScheduler
  2. 生产者提交某个任务:taosScheduleTask
  3. 程序结束时的清理工作:taosCleanUpScheduler

通过搜索上述三个函数的调用, 知道初始化了两个调度器,有三个地方会提交任务。

两个线程池

  1. 定时器里的 tmr 线程池 : 队列长度一万,只有一个线程服务。此线程会执行到期的 timer回调函数
  2. tsc 线程池:队列长度一万,线程数量为所在机器 CPU 核心数的一半。这些线程负责:异步操作如执行语句固定大小滑动窗口流式数据处理

两个生产者

上面提到了,有三个生产者会提交任务给线程池:

  1. timer
  2. stream

了解了清楚使用方、使用场景后,就容易读懂逻辑了。这里是一个标准的操作系统中生产者消费者的问题,用的也是标准解法:使用一个互斥量,两个信号量。线程池使用 pthread 来创建。

关键的数据结构

SSchedQueue 里面就是上述问题中的核心数据结构,除了放置上述提到的互斥量,信号量,还需要一个队列来存储要具体执行的任务。

SSchedMsg 结构来表示线程池任务,包含要执行的具体函数及所需参数。

源码里注释并不多,只能通过看具体实现来了解上述支持的执行模式。看到支持两种模式:执行fp,或者执行 tfp(ahandle, thandle)。

核心调度逻辑

上面提到了生产者,一直没有提到消费者。接着读 sched.c 里的源码,可以看到消费者就是线程池里每个线程的主框架逻辑: taosProcessSchedQueue。平常这些线程处于阻塞状态,等待任务。一旦生产者提交任务后,就会通知到消费者。消费者拿到提交的任务及参数,去执行。执行完之后继续进入上述阻塞的状态,这样周而复始。

这里有个疑问,消费者和生产者之间是异步的。消费完之后,总得有办法通知消费者,这一步在哪里做呢?读到这里可以花点时间翻翻源码,找找答案。

其实秘密也藏在当时提交任务的数据结构里。TDengine 里有样例代码,翻了翻,找到了这个 async demo。可以看到 taos_query_a 就是一个异步的query函数,里面带了 query语句异步执行完成后的回调函数:taos_insert_call_back)。

3. 一些思考

看的时候内心不断在思考、对比,比如优势、劣势是什么?我会怎么实现

优势

为何使用线程池?

  1. 通过固定线程池大小来固定资源开销,而且是程序初始化时申请资源,这在嵌入式设备里是非常重要的,如果资源不够用,那就快速失败,在程序一开始启动时就报错。
  2. 复用了线程,因为创建、销毁线程都是有开销的。这样在频繁创建、销毁线程情况下,可以节省开销,复用之前的线程。
  3. 任务和线程解耦:需要使用多线程的地方,只管提交任务就好了。线程的初始化、运行、状态切换由线程池来负责。

劣势

  1. 操作异步化,对程序员的心智要求更高。需要使用回调函数,需要存储上下文。但是在上述场景里还好, 都是一些固定的逻辑。
  2. 调试较麻烦,不是直来直去的逻辑。需要通过分析上下文及回调函数里的日志来分析问题。

有没有其他实现方式?

如果用 Go 语言实现,会很简单。使用 channel 来做任务分发,本身就是线程安全的。

使用 C 来写,个人觉得会限制 TDengine 的开源参与方。因为现在市场上会 C 的人比较少,而且主要集中在嵌入式领域。而且 C 的生态一般,语言的轮子比较少,所以很多工作都需要自己做,比如 http server,rpc 等。如果让我来设计实现 TDengine,我可能会优先考虑 Rust,既能精准控制内存,又有比较完善的社区,而且语言处于上升期,容易成为其中的明星项目,会有推广优势,比如能吸引一些本身对数据库不怎么关注,但是对 Rust 感兴趣的程序员。

4. 一个思考题

通过搜索 pthread_create 可以发现系统中还有其他创建线程的地方,并没有用到上述的线程池,比如 dnodeMWrite, TcpPoolcachesync等。这些地方为什么没有使用线程池呢?

源码解读 TDengine 中线程池的实现的更多相关文章

  1. 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理

    前提 很早之前就打算看一次JUC线程池ThreadPoolExecutor的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章.之前在分析扩展线程池实现可回调的Future时候曾经提到并发 ...

  2. Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析

    目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...

  3. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  4. JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析

    JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...

  5. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  6. 从源码角度来分析线程池-ThreadPoolExecutor实现原理

    作为一名Java开发工程师,想必性能问题是不可避免的.通常,在遇到性能瓶颈时第一时间肯定会想到利用缓存来解决问题,然而缓存虽好用,但也并非万能,某些场景依然无法覆盖.比如:需要实时.多次调用第三方AP ...

  7. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

  8. 源码角度分析-newFixedThreadPool线程池导致的内存飙升问题

    前言 使用无界队列的线程池会导致内存飙升吗?面试官经常会问这个问题,本文将基于源码,去分析newFixedThreadPool线程池导致的内存飙升问题,希望能加深大家的理解. (想自学习编程的小伙伴请 ...

  9. 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇

    concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...

随机推荐

  1. 存储系列之 XFS文件系统简介

    引言:磁盘容量越来越大,文件系统管理的文件也是越来越大.越来越多,如何破解?唯有快!于是动态分配.B+树开始登上舞台.还记得当年MySQL的索引结构吗,好的作品所见略同. 一.XFS为什么替换Ext4 ...

  2. python设计模式之责任链模式

    python设计模式之责任链模式 开发一个应用时,多数时候我们都能预先知道哪个方法能处理某个特定请求.然而,情况并非总是如此.例如,想想任意一种广播计算机网络,例如最早的以太网实现.在广播计算机网络中 ...

  3. 带你用 Python 实现自动化群控设备

    1. 前言 群控,相信大部分人都不会陌生!印象里是一台电脑控制多台设备完成一系列的操作,更多的人喜欢把它和灰产绑定在一起! 事实上,群控在自动化测试中也被广泛使用!接下来的几篇文章,我将带大家聊聊企业 ...

  4. jraft日志复制

    jraft的日志复制是指从leader往follower复制logEntry的过程. 日志复制从节点成为leader开始.在nodeImpl的becomeLeader中 private void be ...

  5. EXCEL 中数据 批量 填充进 word 中

    工具:Python3.7 需求描述:将EXCEL中 第二行 数据 填在 word 对应位置上,然后保存为 "姓名+任务.docx"文件. 再将EXCEL中 第三行 数据 填在 wo ...

  6. 痞子衡嵌入式:解锁i.MXRTxxx上FlexSPI模块自带的地址重映射(Remap)功能

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT三位数系列隐藏的FlexSPI Remap功能. 前段时间痞子衡写了一篇文章 <利用i.MXRT1060,1010上新 ...

  7. Alpha阶段项目复审(小菜鸡联盟)

    Alpha项目复审 小队:小菜鸡联盟 团队名称 项目名称 评价 排名 『S.L.N』 OnTime 优点:团队分工合理明确,每个成员有一定的开发经验,能用到自己较为熟悉的技术进行开发:在开发初期制定了 ...

  8. 2020.08.31 Unit 10(暂未完成)

    [重点短语] 01.at night 在晚上 02.in a more natural environment 在一个更加自然的环境中 03.all year round 一年到头,终年 04.be ...

  9. e3mall商城的归纳总结7之solr搭建和应用

    敬给读者的话 本文主要应用的技术是solr技术的搭建和应用,本文小编尽量写的更详细一些,让读者在不考虑项目的情况下也能正常完成solr的搭建,说完搭建之后,再说明运行solrj在项目中如何应用solr ...

  10. linux系统工程师修改打开文件数限制代码教程。服务器运维技术

    提示linux文件打开错误,修改linux打开文件数参数. /etc/pam.d/login 添加 session required /lib/security/pam_limits.so 注意看这个 ...