线程

惊群现象

风格不统一 提交于 2020-03-03 05:57:30
惊群 所谓惊群即:多个进程/线程同时阻塞等待同一个事件的发生,如果这个事件发生,那么会唤醒所有进程/线程,但是却只有一个进程/线程会对该事件进行处理,那么其他唤醒的进程/线程会继续休眠阻塞,从而造成性能浪费,这种现象即为惊群。 accept惊群 最常见的即,服务器进程在listen后fork出多个子进程来阻塞accept客户端发起连接,当客户端发起连接时,所有子进程将被唤醒,但是实际上只有一个进程可以获取该连接,而其他进程继续阻塞, 不过新版的linux已经解决了这个问题,即唤醒最先阻塞的进程来获取该连接 epoll惊群 第一种情况是在fork之前创建epollfd,然后主进程fork多个子进程,每个子进程将listenfd加入到epollfd中,当一个连接到来会触发epoll惊群,多个子进程的epoll会被同时触发。造成惊群,不过新版的epoll已经解决了此问题 第二种情况是主进程创建listenfd,主进程创建多个子进程,同时每个子进程有自己的epollfd,每个子进程将listenfd加入到epollfd中,这样当一个连接到来时,会触发惊群,有待解决。NGINX中使用互斥锁和主动的方式去解决惊群问题解决了该惊群问题 nginx解决惊群问题的方法是在每次循环到epoll_wait时,几个子进程竞争互斥锁,获得互斥锁的子进程则将监听fd加到epoll中

java多线程小结

北战南征 提交于 2020-03-03 05:01:59
多线程,同步 1. 多线程 1.1 多线程的优缺点 优点:   1. 提高资源利用率   2. 提升用户体验    缺点:   1. 降低了其他线程的执行概率   2. 造成卡顿   3. 增加的系统,资源压力   4. 多线程情况下的共享资源问题,线程冲突,线程安全问题 1.2 创建自定义线程类的两种方式 class Thread类 Thread类是Runnable接口的实现类,同时提供了很多线程的操作使用的方法。 interface Runnable接口 这里规定了what will be run? 里面只有一个方法 run方法 方式一:  自定义线程类,继承Thread类,重写run方法   创建自定义线程对象,直接调用start方法,开启线程 方式二:  自定义线程类,遵从Runnable接口  使用自定义遵从接口Runnable实现类对象,作为Thread构造方法参数  借助于Thread类对象和start方法,开启线程   【推荐】 以上两种方式,推荐使用方式二 注意 线程的启动方式只有 start(); new Thread(new Runnable() { @Override public void run() { 方法体 } }).start(); MyThread1 myThread1 = new MyThread1(); myThread1.run();

操作系统-原子性与锁机制

让人想犯罪 __ 提交于 2020-03-03 02:39:21
原子性和锁机制 所谓原子性和原子操作即一条或者一系列不可以被中断的指令 原子性的保证: 单核CPU如何保证指令的原子性? 单核CPU下各个指令都是串行的,中断只会发生在一条指令执行完毕,那么自然每个指令都是原子的,如果想要实现单核CPU下多个指令的的原子操作,则可以通过关中断实现 多核CPU如何保证指令的原子性? 多核CPU下由于出现并发问题,所以多个核心可能同时读写同一个内存,所以需要通过一些机制来实现原子操作 多核CPU确保一条指令的原子性,例如递减指令,实际上是三个操作,先读取内存,递减,写回,但是由于是多核CPU,所以即便是一条指令,也无法保证原子性,所以多核总线是通过总线锁来实现多核CPU的原子性的,即在指令执行前先通过总线锁锁住CPU和内存的通信(CPU1向总线发出LOCK#信号,其他处理器便不可以再访问该共享的内存) 总线锁会锁住CPU和内存的通信,开销大(此时并行化的操作变成了串行化的操作,但是),所以可以使用缓存锁,并通过缓存一致性机制来保证原子操作,缓存一致性即MESI协议,介绍如下: 每个CPU有自己的高速缓存,高速缓存以缓存行的形式存在,而MESI就是给每个缓存行保存一个标志位,标志位如下: M:被修改的,当前缓存行中的数据相对内存而言已经被修改了,但是还没有更新到内存中,同时处于该状态的数据只有当前CPU缓存中有,而其他CPU缓存中没有 E:独占的

谈谈Java中的多线程和同步

五迷三道 提交于 2020-03-03 02:15:56
1. 多线程 1.1 多线程的优缺点 优点 提升资源利用率 提高用户体验 缺点: 降低了其他线程的执行概率 用户会感受到软件的卡顿问题 增加的系统,资源压力 多线程情况下的共享资源问题,线程冲突,线程安全问题 1.2 创建自定义线程类的两种方式 class Thread类 Java中的一个线程类 Thread类是Runnable接口的实现类,同时提供了很多线程的操作使用的方法。 interface Runnable接口 这里规定了what will be run? 里面只有一个方法 run方法 方式一: 自定义线程类,继承Thread类,重写run方法 创建自定义线程对象,直接调用start方法,开启线程 方式二: 自定义线程类,遵从Runnable接口 使用自定义遵从接口Runnable实现类对象,作为Thread构造方法参数 借助于Thread类对象和start方法,开启线程 【推荐】 以上两种方式,推荐使用方拾二,遵从Runnable接口来完成自定义线程,不影响正常的继承逻辑,并且可以使用匿名内部类来完成线程代码块的书写 package com . qfedu . a_thread ; /* * 自定义线程类MyThread1继承Thread类 */ class MyThread1 extends Thread { @Override public void run ( )

muduo学习笔记 - 第五章 高效的多线程日志

扶醉桌前 提交于 2020-03-03 00:54:16
第五章 高效的多线程日志 日志有两种意思: 诊断日志 交易日志 本章讲的是前一种日志,文本的供人阅读的日志,通常用于故障诊断和追踪,也可用于性能分析。 日志通常要记录: 收到的每条消息的id(关键字段,长度,hash等) 收到的每条外部消息的全文 发出每条消息的全文,每条消息都有全局唯一的id 关键部分状态的变更,等等 5.1 功能需求 日志库大体分为前端和后端两个部分 前端负责提供应用程序使用的接口API,并生成日志消息 后端负责把日志消息写到目的地 C++日志库的前端大体有两种API风格 printf的格式化输出风格 stream<<风格 stream风格的好处是当输出日志级高于语句的日志级别时,打印日志操作时个空操作,运行时开销接近零 分布式系统中的服务进程而言,日志的目的地只有一个:本地文件。往网络写日志消息时不靠谱的,因为诊断日志功能之一正是诊断网络故障,如果日志消息也是通过网络发到另一台机器就一损俱损… 本地文件作为destination,日志文件的滚动时必须的,可以简化日志的归档实现 文件大小(例如写满10GB就换下一个文件) 时间(例如每天零点新建一个日志文件,不论上一个文件是否写满) 日志文件压缩和归档,不应该是日志库应有的功能,应该交给专门的脚本去做 日志重复利用空间的功能,只会帮倒忙 往文件写日志的常见问题是,如果程序崩溃,最后几条日志信息就会丢失

程序员谈话系列——————解开AQS的神秘面纱

China☆狼群 提交于 2020-03-03 00:52:36
一,谈一谈什么是AQS AQS是一个用来创建锁和同步器的框架,使用AQS能够简单且高效的构造出应用广泛的大量的同步器,比如常用的ReentrantLock,Semaphore‘,其他的诸如ReentrantReadWriteLock,FutureTask等等皆是基于AQS非常轻松容易的构造出符合我们自己需求的同步器。 二,AQS原理分析 AQS核心思想是,如果被请求的共享资源空闲,那么将请求资源的线程设置为有效线程,并且将共享资源设为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待已经被唤醒时锁分配的机制,这个机制时AQS通过CLH队列实现的,将暂时获取步到锁的线程加入到队列当中。CLH队列时一个虚拟的双向队列,即不存在队列实例,仅存在结点之间的关联关系。AQS将每条请求资源的线程封装成CLH锁队列的一个节点,从而实现锁的分配。 AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列来完成排队工作,AQS使用CAS对该同步状态进行原子操作实现对值得修改。 三,AQS对资源得共享方式 1,Exclusive(独占):只有一个线程能执行,如ReentrantLock,公平锁和非公平锁。 2,share(共享),多个线程可以同时执行,比如信号量 Semaphore栅栏 CyclicBarrier闭锁 CountDownLatch等等。 四

muduo网络库学习——日志系统

允我心安 提交于 2020-03-03 00:51:41
日志的使用方式: LOG_INFO << "AAA"; LOG_INFO是一个宏,展开后为: muduo::Logger(__FILE__, __LINE__).stream() << "AAA"; 构造了一个匿名对象Logger,在这个对象构造的时候其实已经写入了文件名和行号。 匿名对象调用.stream()函数拿到一个LogStream对象,由这个LogStream对象重载<<将“AAA”写入LogStream的数据成员FixBuffer对象的data_缓冲区内。 匿名对象在这条语句执行完毕以后会被销毁,因此会调用~muduo::Logger()函数将日志消息输出至目的地(标准输出或者磁盘的日志文件); 日志的流程: Logger——Impl——LogStream——operator<<——LogStream的FixBuffer内——g_output——g_flush 高性能日志(异步日志)所在: 由于磁盘IO是移动磁头的方式来记录文件的,其速度与CPU运行速度并不在一个数量级上。因此业务线程中应该避免进行磁盘IO以防止业务得不到及时的处理。 在多线程程序中,业务线程应该专注与其业务逻辑的运算,用另外一个独立的线程来将日志消息写入磁盘。 在muduo的日志系统中,分为前端和后端。前端是业务线程产生一条条的日志消息。后端是日志线程,将日志消息写入文件。 业务线程有多个

sqlalchemy 数据库操作

故事扮演 提交于 2020-03-03 00:28:08
1、简介 一种ORM 2、安装 pip3 install -i https://pypi.douban.com/simple sqlalchemy 3、连接数据库 from sqlalchemy import create_engine engine = create_engine( "mysql+pymysql://root:密码@127.0.0.1:3306/数据库名称?charset=utf8", max_overflow=0, # 超过连接池大小外最多创建的连接 pool_size=5, # 连接池大小 pool_timeout=30, # 池中没有线程最多等待的时间,否则报错 pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置) ) 4、创建/删除表(包含连接数据库) a、表类 from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column from sqlalchemy import Integer,String Base = declarative_base() class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True)

悲观所与乐观锁

半腔热情 提交于 2020-03-03 00:13:09
一、乐观锁 总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。 version方式: 一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。 核心SQL代码: update table set x=x+1, version=version+1 where id=#{id} and version=#{version}; CAS操作方式: 即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。 一、悲观锁 总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中

Python_线程

三世轮回 提交于 2020-03-02 22:26:52
线程概念的引入背景 进程   之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。 有了进程为什么要有线程   进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上: 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。   如果这两个缺点理解比较困难的话,举个现实的例子也许你就清楚了:如果把我们上课的过程看成一个进程的话,那么我们要做的是耳朵听老师讲课,手上还要记笔记,脑子还要思考问题,这样才能高效的完成听课的任务。而如果只提供进程这个机制的话