这篇文章是对上篇文章的一个补充,主要环绕下面两点展开。one-connection-per-thread的实现方式以及线程池中epoll的使用。

one-connection-per-thread

依据scheduler_functions的模板,我们也能够列出one-connection-per-thread方式的几个关键函数。

static scheduler_functions con_per_functions=

{ max_connection+1, // max_threads

NULL,

NULL,

NULL, // init

Init_new_connection_handler_thread, // init_new_connection_thread

create_thread_to_handle_connection, // add_connection

NULL, // thd_wait_begin

NULL, // thd_wait_end

NULL, // post_kill_notification

one_thread_per_connection_end, // end_thread

NULL // end

};

1.init_new_connection_handler_thread

这个接口比較简单,主要是调用pthread_detach。将线程设置为detach状态,线程结束后自己主动释放全部资源。

2.create_thread_to_handle_connection

这个接口是处理新连接的接口,对于线程池而言,会从thread_id%group_size相应的group中获取一个线程来处理,而one-connection-per-thread方式则会推断是否有thread_cache能够使用,假设没有则新建线程来处理。详细逻辑例如以下:

(1).推断缓存的线程数是否使用完(比較blocked_pthread_count 和wake_pthread大小)

(2).若还有缓存线程,将thd增加waiting_thd_list的队列,唤醒一个等待COND_thread_cache的线程

(3).若没有。创建一个新的线程处理,线程的入口函数是do_handle_one_connection

(4).调用add_global_thread增加thd数组。

3.do_handle_one_connection

这个接口被create_thread_to_handle_connection调用,处理请求的主要实现接口。

(1).循环调用do_command。从socket中读取网络包,而且解析运行。

(2). 当远程client发送关闭连接COMMAND(比方COM_QUIT,COM_SHUTDOWN)时,退出循环

(3).调用close_connection关闭连接(thd->disconnect());

(4).调用one_thread_per_connection_end函数,确认能否够复用线程

(5).依据返回结果,确定退出工作线程还是继续循环运行命令。

4.one_thread_per_connection_end

推断能否够复用线程(thread_cache)的主要函数,逻辑例如以下:

(1).调用remove_global_thread。移除线程相应的thd实例

(2).调用block_until_new_connection推断能否够重用thread

(3).推断缓存的线程是否超过阀值,若没有,则blocked_pthread_count++;

(4).堵塞等待条件变量COND_thread_cache

(5).被唤醒后,表示有新的thd须要重用线程,将thd从waiting_thd_list中移除,使用thd初始化线程的thd->thread_stack

(6).调用add_global_thread增加thd数组。

(7).假设能够重用,返回false,否则返回ture

线程池与epoll

在引入线程池之前,server层仅仅有一个监听线程。负责监听mysqlport和本地unixsocket的请求。对于每一个新的连接,都会分配一个独立线程来处理,因此监听线程的任务比較轻松。mysql通过poll或select方式来实现IO的多路复用。引入线程池后。除了server层的监听线程,每一个group都有一个监听线程负责监听group内的全部连接socket的连接请求,工作线程不负责监听,仅仅处理请求。对于overscribe为1000的线程池设置。每一个监听线程须要监听1000个socket的请求。监听线程採用epoll方式来实现监听。

Select,poll,epoll都是IO多路复用机制。IO多路复用通过一种机制。能够监听多个fd(描写叙述符)。比方socket。一旦某个fd就绪(读就绪或写就绪),能够通知程序进行对应的读写操作。epoll相对于select和poll有了非常大的改进,首先epoll通过epoll_ctl函数注冊,注冊时,将全部fd拷贝进内核,仅仅拷贝一次不须要反复拷贝,而每次调用poll或select时,都须要将fd集合从用户空间复制到内核空间(epoll通过epoll_wait进行等待);其次,epoll为每一个描写叙述符指定了一个回调函数,当设备就绪时,唤醒等待者,通过回调函数将描写叙述符增加到就绪链表,无需像select。poll方式採用轮询方式。最后select默认仅仅支持1024个fd,epoll则没有限制,详细数字能够參考cat
/proc/sys/fs/file-max的设置。

epoll贯穿在线程池使用的过程中,以下我就epoll的创建。使用和销毁生命周期来描写叙述epoll在线程中是怎样使用的。

  1. 线程池初始化。epoll通过epoll_create函数创建epoll文件描写叙述符,实现函数是thread_group_init。
  2. port监听线程监听到请求后,创建socket,并创建THD和connection对象,放在相应的group队列中。
  3. 工作线程获取该connection对象时。若还未登录,则进行登录验证
  4. 若socket还未注冊到epoll,则调用epoll_ctl进行注冊,注冊方式是EPOLL_CTL_ADD,并将connection对象放入epoll_event结构体中
  5. 若是老连接的请求,仍然须要调用epoll_ctl注冊,注冊方式是EPOLL_CTL_MOD
  6. group内的监听线程调用epoll_wait来监听注冊的fd,epoll是一种同步IO方式,所以会进行等待
  7. 请求到来时。获取epoll_event结构体中的connection,放入到group中的队列
  8. 线程池销毁时。调用thread_group_close将epoll关闭。

备注:

1.注冊在epoll的fd,若请求就绪。则将相应的event放入到events数组,并将该fd的事务类型清空,因此对于老的连接请求。依旧须要调用epoll_ctl(pollfd, EPOLL_CTL_MOD, fd, &ev)来注冊。

线程池函数调用关系

(1)创建epoll

tp_init->thread_group_init->tp_set_threadpool_size->io_poll_create->epoll_create

(2)关闭epoll

tp_end->thread_group_close->thread_group_destroy->close(pollfd)

(3)关联socket描写叙述符

handle_event->start_io->io_poll_associate_fd->io_poll_start_read->epoll_ctl

(4)处理连接请求

handle_event->threadpool_process_request->do_command->dispatch_command->mysql_parse->mysql_execute_command

(5)工作线程空暇时

worker_main->get_event->pthread_cond_timedwait

等待thread_pool_idle_timeout后。退出。

(6)监听epoll

worker_main->get_event->listener->io_poll_wait->epoll_wait

(7)port监听线程

main->mysqld_main->handle_connections_sockets->poll

one-connection-per-thread函数调用关系

(1) 工作线程等待请求

handle_one_connection->do_handle_one_connection->do_command->

my_net_read->net_read_packet->net_read_packet_header->net_read_raw_loop->

vio_read->vio_socket_io_wait->vio_io_wait->poll

备注:与线程池的工作线程有监听线程帮助其监听请求不同,one-connection-per-thread方式的工作线程在空暇时。会调用poll堵塞等待网络包过来;

而线程池的工作线程仅仅须要专心处理请求就可以,所以使用也更充分。

(2)port监听线程

与线程池的(7)同样

參考文档

http://www.cnblogs.com/Anker/p/3265058.html

http://blog.csdn.net/zhanglu5227/article/details/7960677

MySQL具体解释(8)----------MySQL线程池总结(二)的更多相关文章

  1. juc线程池原理(二):ThreadPoolExecutor的成员变量介绍

    概要 线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析ThreadPoolExecutor类,来了解线程池的原理. ThreadPoolExecutor数据结构 Thread ...

  2. Java 线程池(二)

    简介 在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线 ...

  3. mysql小白系列_03 体系结构-线程池

    thread pool的原理是什么? 为什么用double write就能解决page坏的问题? Innodb redo log 与 binlog有什么区别?有了Innodb redo log为什么还 ...

  4. Android线程池(二)

    本篇主要介绍Android自带的线程池的管理. 包含开始任务.重新加载.添加删除任务等,示例代码如下: package com.jiao.threadpooltest; import java.uti ...

  5. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  6. android线程与线程池-----线程池(二)《android开发艺术与探索》

    android 中的线程池 线程池的优点: 1 重用线程池中的线程,避免了线程的创建和销毁带来的性能开销 2 能有效的控制最大并发数,避免大量线程之间因为喜欢抢资源而导致阻塞 3 能够对线程进行简单的 ...

  7. java线程池技术(二): 核心ThreadPoolExecutor介绍

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...

  8. Java之线程池(二)

    关于线程和线程池的学习,我们可以从以下几个方面入手: 第一,什么是线程,线程和进程的区别是什么 第二,线程中的基本概念,线程的生命周期 第三,单线程和多线程 第四,线程池的原理解析 第五,常见的几种线 ...

  9. c#自己实现线程池功能(二)

    介绍 在上一篇c#自己实现线程池功能(一)中,我们基本实现了一个能够执行的程序.而不能真正的称作线程池.因为是上篇中的代码有个致命的bug那就是没有任务是并非等待,而是疯狂的进行while循环,并试图 ...

随机推荐

  1. Visual Studio写Cuda代码

    1. 正常新建一个项目   2. 在项目中右键, build 选项中选择 CUDA 编译器   3. 项目属性中设置 CUDA 链接库 和 头文件 编译参数等   4. 完成     cu cuh 文 ...

  2. JDBC基础01

    今日知识 1. JDBC基本概念2. 快速入门3. 对JDBC中各个接口和类详解 JDBC: 1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言操作 ...

  3. golang图片压缩

    package main import (    //"encoding/json"    "fmt"    //"os"    //&qu ...

  4. 第5章分布式系统模式 在 .NET 中使用 DataSet 实现 Data Transfer Object

    要在 .NET Framework 中实现分布式应用程序.客户端应用程序需要显示一个窗体,该窗体要求对 ASP.NET Web Service 进行多个调用以满足单个用户请求.基于性能方面的考虑,我们 ...

  5. 用命令行在本地创建一个库并上传到Github

    1  如何在本地创建一个仓库并上传到github? 基本步骤: $ mkdir blog //在桌面上创建一个叫"blog"的目录 $ cd blog //"cd blo ...

  6. Linux集群搭建与Hadoop环境搭建

    今天是8月19日,距离开学还有15天,假期作业完成还是遥遥无期,看来开学之前的恶补是躲不过了 今天总结一下在Linux环境下安装Hadoop的过程,首先是对Linux环境的配置,设置主机名称,网络设置 ...

  7. jQuery中样式和属性模块简单分析

    1.行内样式操作 目标:扩展框架实现行内样式的增删改查 1.1 创建 css 方法 目标:实现单个样式或者多个样式的操作 1.1.1 css方法 -获取样式 注意:使用 style 属性只能获取行内样 ...

  8. android黑科技系列——手机端破解神器MT的内购VIP功能破解教程

    一.前言 在破解app的时候,我们现在几乎都是在PC端进行操作,但是之前bin神的MT管理器,可以在手机端直接破解,不过也有很大的局限性,但是对于一些简单的app破解没问题的.这个工具其实原理也很简单 ...

  9. 6 Python+Selenium的元素定位方法(CSS)

    [环境] python3.6+selenium3.0.2+Firefox50.0+win7 [定位方法] 1.方法:find_element_by_css_selector('xx') CSS的语法比 ...

  10. jQuery访问json文件(一个例子)

    保存网址 打开时 点开一个类型 当点开一个类型,其他类型隐藏 回到所有类型 没有错,左下角有个这是什么样子的图标 做到了什么: 1.从json文件中取得网址,并根据访问次数排列,放到前面: 2.就是1 ...