select、poll、epoll的区别

关于NIO:神之博客小眼睛聊技术 (infoq.cn) 这仨能够同时监控多个文件描述符的可读可写情况,当其中的某些文件描述符可读或者可写时,这仨方法就会返回可读以及可写的文件描述符个数。并让用户线程进行处理。 select fd_set 是使用数组实现的 select的显著缺点: 1.fd_size 有限制 1024 bitmap ​ fd【i】 = accept() ​ 2.fdset不可重用,新的fd进来,重新创建 ​ 3.用户态和内核态拷贝产生开销 ​ 4.O(n)时间复杂度的轮询 ​ 成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0 ​ 具有超时时间 poll 基于结构体存储fd struct pollfd{ int fd; short events; short revents; // 可重用,不像bitmap } poll解决了select的1,2两点缺点 epoll 解决了select的1,2,3,4 不需要轮询,时间复杂度为O(1) epoll_create 创建一个白板 存放fd_events epoll_ctl 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上 epoll_wait 通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符 epoll对文件描述符的操作有两种模式:LT(level tri gger)和ET(edge trigger)。LT模式是默认模式,LT模式与ET模式的区别如下: LT模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件。 ET模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。 1. LT模式 LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的。 2. ET模式 ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)...

April 30, 2022 · 1 min · Rufus

《InnoDB技术内幕》读书笔记

Mysql体系结构和存储引擎 基本概念  数据库:物理操作系统文件或其他形式文件类型的集合。(是文件的集合,是依照某种数据模型组织起来并存放于二级存储器中的数据集合。)  数据库实例:由数据库后台进程/线程以及一个共享内存区域组成。(是应用程序,是位于用户与操作系统之间的一层数据管理软件,用户对数据库的任何操作都是在数据库实例下进行的,应用程序只有通过数据库实例才能和数据库打交道。)一个实例对应一个数据库,但在集群环境下,一个数据库可能对应多个实例 数据库是由一个一个文件组成的,如果要对这些文件执行诸如SELECT、INSERT、UPDATE和DELETE之类的操作,不能通过简单的操作文件来更改数据库的内容,需要通过数据库实例来完成对数据库的操作。 Mysql是一个单线程多进程的应用 Mysql体系架构 组成部分: 连接池组件 管理服务和工具组件 SQL接口组件 查询分析器组件 优化器组件 cache组件 插件式存储引擎 (最重要的特色) 物理文件  MySQL区别于其他数据库的最重要的特点是插件式的表存储引擎。(存储引擎是底层物理结构的实现,它是基于表的,而不是基于数据库) 常见引擎 InnoDB: InnoDB存储引擎支持事务,主要面向在线事务处理(OLTO)方面的应用。 特点:行锁设计,支持外键,并支持非锁定读(即默认情况下读取操作不会产生锁)。 MSQL在windoes版本下的InnoDB是默认的存储引擎。 InnoDB将数据放在一个逻辑的表空间中,这个表空间就想黑盒一样由InnoDB自身进行管理。从MySQL4.1版本开始,它可以将每个InnoDB存储引擎的表单独放在一个独立的ibd文件中。 InnoDB通过使用多版本并发控制(MVCC)来获得高并发性,并且实现了SQL标准中的4种隔离级别,默认为REPEATABLE级别,同时使用一种被称为next-key locking的策略来避免幻读。 除此之外,InnoDB还提供了插入缓冲、二次写、自适应哈希索引、预读等高性能和高可用的功能。 对于表中数据的存储,InnoDB存储引擎采用了聚集的方式,这种方式类似于Oracle的索引聚集表。每张表的存储都按主键的顺序存放,如果没有显式地在表定义时指定主键,InnoDB存储引擎会为每一行生成一个6字节的ROWID,并以此作为主键。 MyISAM: 特点:不支持事务、表锁和全文索引,对于一些OLAP(在线分析处理)操作速度快。除windows版本外,是所有其他版本默认的存储引擎。 MyISAM存储引擎表由MYD和MYI组成,MYD用来存放数据文件,MYI用来存放索引文件。 对于MyISAM存储引擎表,Mysql数据库只缓存其索引文件,数据文件的缓存交由操作系统本身来完成,这与其他使用LRU算法缓存数据的大部分数据库大不相同。 Memory: 基于内存,表结构存储在文件中,但是数据存在内存 没有持久化机制 只支持表锁 既然Mysql有内存引擎Memory,为什么还需要Redis_秦偏执的博客-CSDN博客 没有持久化机制 结构不灵活,需要定义表结构,Redis支持很多数据结构 MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY) - 于果alpha - 博客园 InnoDB引擎 体系架构 简略版 详细版 说白了就是一堆线程操作一堆内存和一堆文件 后台线程 InnoDB是多线程模型,后台有多个不同的线程,分别处理不同的任务。 Master Thread,在各种loop中跳转,低版本中,负责脏页刷新,合并插入缓存,undo 页的回收 IO Thread,负责 IO 请求 Purge Thread,1....

April 28, 2022 · 3 min · Rufus

二次学习之《深入理解java虚拟机》读书笔记

之前跟着视频学完,总感觉心里不踏实,还是看一看书吧 JVM构成 程序计数器(线程私有) 用于保存JVM中下一条所要执行的指令的地址 CPU会为每个线程分配时间片,当当前线程的时间片使用完以后,CPU就会去执行另一个线程中的代码 程序计数器是每个线程所私有的,当另一个线程的时间片用完,又返回来执行当前线程的代码时,通过程序计数器可以知道应该执行哪一句指令 唯一一个不会存在内存溢出的区 虚拟机栈(线程私有) 每个线程运行需要的内存空间,称为虚拟机栈JVM stacks 每个栈由多个栈帧组成,对应着每次调用方法时所占用的内存 每个线程只能有一个活动栈帧,对应着当前正在执行的方法, 在栈的顶部 本地方法栈 与JVM栈类似,但是服务的对象不一样,本地方法栈是为native方法服务的 hotspot中虚拟机栈与本地方法栈合二为一 堆(线程共有) 所有线程共享,JVM创建的时候就创建了 存放实例化对象,GC的集中区域就是堆区 所有的对象实例及数组都分配在堆上(实际上因为即时编译技术,有些对象被优化到栈上分配) 在JDK1.7 字符串常量池被从方法区拿到了堆中 方法区 所有线程共享,JVM创建的时候就创建了 用于存储类定义信息,常量,静态变量,即时编译器编译后的代码缓存数据。 运行时常量池也在这儿 在JDK1.6及之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代(位于堆内存中) 在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代 在JDK1.8 hotspot移除了永久代用元空间取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(堆外内存) 作者:Himeros 链接:https://www.zhihu.com/question/377418017/answer/1062033254 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 一般情况下,方法区中的数据是不会被回收的。 编译后的字节码指令也在这儿,所谓的pc存储的地址,就是指向这个区域。 在本地内存通过元空间实现(jdk8及之后)...

April 20, 2022 · 8 min · Rufus

计算机网络

计算机网络 总览 OSI七层模型和TCP/IP五层模型 OSI是理论上的(复杂冗余),TCP/IP是实际上的。 应用层 GET 和 POST 的区别 get 提交的数据会放在 URL 之后,并且请求参数会被完整的保留在浏览器的记录里,由于参数直接暴露在 URL 中,可能会存在安全问题,因此往往用于获取资源信息。而 post 参数放在请求主体中,并且参数不会被保留,相比 get 方法,post 方法更安全,主要用于修改服务器上的资源。 get 请求只支持 URL 编码,post 请求支持多种编码格式。 get 只支持 ASCII 字符格式的参数,而 post 方法没有限制。 get 提交的数据大小有限制(这里所说的限制是针对浏览器而言的),而 post 方法提交的数据没限制. get 方式需要使用 Request.QueryString 来取得变量的值,而 post 方式通过 Request.Form 来获取。 get 方法产生一个 TCP 数据包,post 方法产生两个(并不是所有的浏览器中都产生两个)。 HTTP 与 HTTPs 的工作方式【建立连接的过程】 HTTP HTTP(Hyper Text Transfer Protocol: 超文本传输协议) 是一种简单的请求 - 响应协议,被用于在 Web 浏览器和网站服务器之间传递消息。HTTP 使用 TCP(而不是 UDP)作为它的支撑运输层协议。其默认工作在 TCP 协议 80 端口,HTTP 客户机发起一个与服务器的 TCP 连接,一旦连接建立,浏览器和服务器进程就可以通过套接字接口访问 TCP。客户机从套接字接口发送 HTTP 请求报文和接收 HTTP 响应报文。类似地,服务器也是从套接字接口接收 HTTP 请求报文和发送 HTTP 响应报文。其通信内容以明文的方式发送,不通过任何方式的数据加密。当通信结束时,客户端与服务器关闭连接。...

April 16, 2022 · 5 min · Rufus

java多线程

并发与并行 我们经常听到并发编程,那么这个并发代表的是什么意思呢?而与之相似的并行又是什么意思?它们之间有什么区别? 比如现在一共有三个工作需要我们去完成。 顺序执行 顺序执行其实很好理解,就是我们依次去将这些任务完成了: 实际上就是我们同一时间只能处理一个任务,所以需要前一个任务完成之后,才能继续下一个任务,依次完成所有任务。 并发执行 并发执行也是我们同一时间只能处理一个任务,但是我们可以每个任务轮着做(时间片轮转): 只要我们单次处理分配的时间足够的短,在宏观看来,就是三个任务在同时进行。 而我们Java中的线程,正是这种机制,当我们需要同时处理上百个上千个任务时,很明显CPU的数量是不可能赶得上我们的线程数的,所以说这时就要求我们的程序有良好的并发性能,来应对同一时间大量的任务处理。学习Java并发编程,能够让我们在以后的实际场景中,知道该如何应对高并发的情况。 并行执行 并行执行就突破了同一时间只能处理一个任务的限制,我们同一时间可以做多个任务: 比如我们要进行一些排序操作,就可以用到并行计算,只需要等待所有子任务完成,最后将结果汇总即可。包括分布式计算模型MapReduce,也是采用的并行计算思路。 再谈锁机制 谈到锁机制,相信各位应该并不陌生了,我们在JavaSE阶段,通过使用synchronized关键字来实现锁,这样就能够很好地解决线程之间争抢资源的情况。那么,synchronized底层到底是如何实现的呢? 我们知道,使用synchronized,一定是和某个对象相关联的,比如我们要对某一段代码加锁,那么我们就需要提供一个对象来作为锁本身: public static void main(String[] args) { synchronized (Main.class) { //这里使用的是Main类的Class对象作为锁 } } 我们来看看,它变成字节码之后会用到哪些指令: 其中最关键的就是monitorenter指令了,可以看到之后也有monitorexit与之进行匹配(注意这里有2个),monitorenter和monitorexit分别对应加锁和释放锁,在执行monitorenter之前需要尝试获取锁,每个对象都有一个monitor监视器与之对应,而这里正是去获取对象监视器的所有权,一旦monitor所有权被某个线程持有,那么其他线程将无法获得(管程模型的一种实现)。 在代码执行完成之后,我们可以看到,一共有两个monitorexit在等着我们,那么为什么这里会有两个呢,按理说monitorenter和monitorexit不应该一一对应吗,这里为什么要释放锁两次呢? 首先我们来看第一个,这里在释放锁之后,会马上进入到一个goto指令,跳转到15行,而我们的15行对应的指令就是方法的返回指令,其实正常情况下只会执行第一个monitorexit释放锁,在释放锁之后就接着同步代码块后面的内容继续向下执行了。而第二个,其实是用来处理异常的,可以看到,它的位置是在12行,如果程序运行发生异常,那么就会执行第二个monitorexit,并且会继续向下通过athrow指令抛出异常,而不是直接跳转到15行正常运行下去。 实际上synchronized使用的锁就是存储在Java对象头中的,我们知道,对象是存放在堆内存中的,而每个对象内部,都有一部分空间用于存储对象头信息,而对象头信息中,则包含了Mark Word用于存放hashCode和对象的锁信息,在不同状态下,它存储的数据结构有一些不同。 重量级锁 在JDK6之前,synchronized一直被称为重量级锁,monitor依赖于底层操作系统的Lock实现,Java的线程是映射到操作系统的原生线程上,切换成本较高。而在JDK6之后,锁的实现得到了改进。我们先从最原始的重量级锁开始: 我们说了,每个对象都有一个monitor与之关联,在Java虚拟机(HotSpot)中,monitor是由ObjectMonitor实现的: ObjectMonitor() { _header = NULL; _count = 0; //记录个数 _waiters = 0, _recursions = 0; _object = NULL; _owner = NULL; _WaitSet = NULL; //处于wait状态的线程,会被加入到_WaitSet _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; FreeNext = NULL ; _EntryList = NULL ; //处于等待锁block状态的线程,会被加入到该列表 _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; } 每个等待锁的线程都会被封装成ObjectWaiter对象,进入到如下机制:...

April 12, 2022 · 35 min · Rufus