精华内容
下载资源
问答
  • 2019-03-15 11:23:16

    什么是进程?
    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
    而一个进程又是由多个线程所组成的。


    什么是线程?
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,
    即不同的线程可以执行同样的函数。


    什么是多线程?
    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,
    也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。


    多线程的好处:
    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,
    这样就大大提高了程序的效率。 


    多线程的不利方面:
    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 
    多线程需要协调和管理,所以需要CPU时间跟踪线程; 
    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
    线程太多会导致控制太复杂,最终可能造成很多Bug;


    多线程与单线程的区别
    生活举例
    你早上上班,正要打卡的时候,手机响了。。你如果先接了电话,等接完了,在打卡,就是单线程。
    如果你一手接电话,一手打卡。就是多线程。
    2件事的结果是一样的。。你接了电话且打了卡。

     

    多线程处理的优点

    同步应用程序的开发比较容易,但由于需要在上一个任务完成后才能开始新的任务,所以其效率通常比多线程应用程序低。如果完成同步任务所用的时间比预计时间长,应用程序可能会不响应。多线程处理可以同时运行多个过程。例如,文字处理器应用程序在您处理文档的同时,可以检查拼写(作为单独的任务)。由于多线程应用程序将程序划分成独立的任务,因此可以在以下方面显著提高性能: 
    多线程技术使程序的响应速度更快,因为用户界面可以在进行其他工作的同时一直处于活动状态。 
    当前没有进行处理的任务可以将处理器时间让给其他任务。 
    占用大量处理时间的任务可以定期将处理器时间让给其他任务。 
    可以随时停止任务。 
    可以分别设置各个任务的优先级以优化性能。 

    是否需要创建多线程应用程序取决于多个因素。在以下情况下,最适合采用多线程处理:
    耗时或大量占用处理器的任务阻塞用户界面操作。 
    各个任务必须等待外部资源(如远程文件或 INTERNET 连接)。 

    例如,用于跟踪 WEB 页上的链接并下载满足特定条件的文件的 INTERNET 应用程序“ROBOT”。这种应用程序可以依次同步下载各个文件,也可以使用多线程同时下载多个文件。多线程方法比同步方法的效率高很多,因为即使在某些线程中远程 WEB 服务器的响应非常慢,也可以下载文件。

    下面是多线程的例子
    还在DOS时代,人们就在寻求一种多任务的实现。于是出现了TSR类型的后台驻留程序,比较有代表性的有SIDE KICK、VSAFE等优秀的TSR程序,这类程序的出现和应用确实给用户使用计算机带来了极大的方便,比如SIDE KICK,们编程可以在不用进编辑程序的状态下,一边编辑源程序,一边编译运行,非常方便。但是,DOS单任务操作系统的致命缺陷注定了在DOS下不可能开发出真正的多任务程序。进入WINDOWS3.1时代,这种情况依然没有根本的改变,一次应用只能做一件事。比如数据库查询,除非应用编得很好,在查询期间整个系统将不响应用户的输入。
     进入了WINDOWS NT和WINDOWS 9X时代,情况就有了彻底的改观,操作系统从真正意义上实现了多任务(严格地说,WIN9X还算不上)。一个应用程序,在需要的时候可以有许多个执行线程,每个线程就是一个小的执行程序,操作系统自动使各个线程共享CPU资源,确保任一线程都不能使系统死锁。这样,在编程的时候,可以把费时间的任务移到后台,在前台用另一个线程接受用户的输入。对那些对实时性要求比较高的编程任务,如网络客户服务、串行通信等应用时,多线程的实现无疑大大地增强了程序的可用性和稳固性。

    =====================================================================================

    坏处:增加了调度和管理的开销,带来了一些不确定性,需要复杂的同步机制,避免死锁等等。
    好处:一定程度上提高响应速度,在多核的情况下还是更能充分利用CPU资源的。

    =====================================================================================

    单线程的也就是程序执行时,所跑的程序路径(处理的东西)是连续顺序下来的,必须前面的处理好,后面的才会执行到。   
    (未细看)单线程和多线程的优缺点 - Daniel - 休子的博客       多线程嘛,举个例子也就是说程序可以同时执行2个以上相同类似的操作,比如一些搜索代理或者群发email的多线程软件,由于操作一次需要网络的返回信息   花的时间比较长,而对cpu来说却是空闲的,如果是一个一个顺序执行,那么搜索几千个IP就会花上好久好久。   而如果用多线程就可以在等待期间   加入其他的搜索,然后等待,这样可以提高效率。不过多线程和多进程公用一些资源时要考虑的问题好像也是一样的,对于一些公共资源或者公共变量的访问和修改时要注意特别的,需要一些锁定什么的,还有顺序问题的考虑。  
           多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。每个程序执行时都会产生一个进程,而每一个进程至少要有一个主线程。这个线程其实是进程执行的一条线索,除了主线程外你还可以给进程增加其它的线程,也即增加其它的执行线索,由此在某种程度上可以看成是给一个应用程序增加了多任务功能。当程序运行后,您可以根据各种条件挂起或运行这些线程,尤其在多CPU的环境中,这些线程是并发运行的。多线程就是在一个进程内有多个线程。从而使一个应用程序有了多任务的功能。多进程技术也可以实现这一点,但是创建进程的高消耗(每个进程都有独立的数据和代码空间),进程之间通信的不方便(消息机制),进程切换的时间太长,这些导致了多线程的提出,对于单CPU来说(没有开启超线程),在同一时间只能执行一个线程,所以如果想实现多任务,那么就只能每个进程或线程获得一个时间片,在某个时间片内,只能一个线程执行,然后按照某种策略换其他线程执行。由于时间片很短,这样给用户的感觉是同时有好多线程在执行。但是线程切换是有代价的,因此如果采用多进程,那么就需要将线程所隶属的该进程所需要的内存进行切换,这时间代价是很多的。而线程切换代价就很少,线程是可以共享内存的。所以采用多线程在切换上花费的比多进程少得多。但是,线程切换还是需要时间消耗的,所以采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。上述结果只是针对单CPU,如果对于多CPU或者CPU采用超线程技术的话,采用多线程技术还是会提高程序的执行速度的。因为单线程只会映射到一个CPU上,而多线程会映射到多个CPU上,超线程技术本质是多线程硬件化,所以也会加快程序的执行速度。

    ====================================================================================

    如果线程出现死锁,唯一能证明的就是应用程序有问题,这并不是线程的缺点。

    线程相对于进程的优点:
    1、开销小
    2、资源共享性好。

    线程相对于进程的缺点:
    1、共享资源需要耗费一定的锁资源,同步相对复杂。
    2、一个线程崩溃可能导致整个进程崩溃,这个当然是自己的应用程序有问题

    ====================================================================================

    CPU是以时间片的方式为进程分配CUP处理时间的,当一个进程以同步的方式去完成几件事情时,此进程必须完成了第一件事情以后再做第二件事,如此按顺序地向CPU请求完成要做的事情。在此单线程的工作模式下,如果把CUP看作是一共有100个时间片的话,CPU可能一直都只是花了其中的10个时间片来处理当前进程所要做的事情,只是用到了CPU的10%的时间片,而其他时间都白白浪费了,当然,实际上CPU的工作模式还是做完一件事以后再去做另一件事,只是CUP的处理速度非常快,很快就处理完成所请求的情事。

        为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而互不干扰,如当前进程要完成三件事情1、2、3,那么CPU会分别用10%的时间来同时处理这3件事情,从而让CPU的使用率达到了30%,大大地提高了CPU的利用率。多线程的好处在处理一些特殊的场合其优势尤其明显。比如下载文件,你要一边下载一边显示进度一边保存,在这种情况下,如果没有用多线程的话,没有意外的话一般都会把主线程阻塞,比如进度条的进度根本没有随着已下载的量而变化,堪至是整个窗体都动不了,用多线程就可以很好地解决这个问题。

        这里有一个生活实例可能更好地去理解多线程:回去看你女朋友做饭,正常的话她都会把洗好的菜(肉)先放到锅里煮,然后一边洗别的菜或处理别的事情,如:洗碗、收拾桌台准备开饭,人还是一个人,但她同时做几件事情,这样就可以大大地提高效率。总的一句话就是:CPU还是要花同样多的时间去完成所有的事情,但多线程可以让CPU掺插地同时做多件事情,在视觉上让用户觉得计算机在同时帮他处理多件事情,更好地改善用户体验。

         了解了多线程的好处以后,就要了解应该在什么样的情况下使用多线程技术。因为并不是说所有情况下用多线程都是好事,因为多线程的情况下,CPU还要花时间去维护,CPU处理各线程的请求时在线程间的切换也要花时间,所以一般情况下是可以不用多线程的,用了有时反而会得不偿失。大多情况下,要用到多线程的主要是需要处理大量的IO操作时或处理的情况需要花大量的时间等等,比如:读写文件、视频图像的采集、处理、显示、保存等。

     

    转载于:http://blog.csdn.net/u012134199/article/details/46290465

    更多相关内容
  • 单线程

    千次阅读 2020-03-21 21:31:25
    简单的说,单线程就是进程中只有一个线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。以上是main方法,是一个主线程。多线程由一个或者多个线程组成的程序就是多...

    在这里插入图片描述
    简单的说,单线程就是进程中只有一个线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。以上是main方法,是一个主线程。多线程由一个或者多个线程组成的程序就是多线程,Java中,一定是从主线程开始执行(main方法),然后在主线程的某个位置启动新的线程。二、线程的基本操作2.1 创建创建线程的两种方法1、继承java.lang.Thread上述代码中,MyThread类继承了类java.lang.Thread,并覆写了run方法。主线程从main方法开始执行,当主线程执行至t.start()时,启动新线程(注意此处是调用start方法,不是run方法),新线程会并发执行自身的run方法。2、实现java.lang.Runnable接口 Mythread通过实现Runnable接口,覆写了run方法,实现创建线程的过程,与继承Thread类创建的线程是一样的结果。实际Thread类里边也是通过实现Runnable接口,唯一不同的就是这里边的run方法是空的。里边具体的实现交由外层调用类采用override实现。注意事项:多线程的运行过程中,如果主线程已经执行完成,但是其子线程还在执行,那表明程序还未结束,等到所有的线程都执行完成时,程序才算结束。 2.2 暂停线程中的暂停操作是调用sleep实现的,此方法可以指定对应的时间,实现让线程暂停多久。值得注意的是 线程中如果持有锁,sleep结束之前锁会一直持有,到达时间后才会释放线程调用sleep方法可以实现暂停1s的输出效果,如果在线程执行过程中出现异常,当前线程就会被interrupt,此时异常InterrunpterException就会发生。2.3互斥Java中线程的共享互斥操作,会使用synchronized关键字。线程共享互斥的架构称为监视(monitor),而获取锁有时也称为“持有(own)监视”。每个锁在同一时刻,只能由一个线程持有。注意:synchronized方法或声明执行期间,如程序遇到任何异常或return,线程都会释放锁。1、synchronized方法Java示例1://synchronized实例方法public synchronized void deposit(int m) { System.out.print(“This is synchronized method.”);}注:synchronized实例方法采用this锁(即当前对象)去做线程的共享互斥。Java示例2://synchronized类方法public static synchronized void deposit(int m) { System.out.print(“This is synchronized static method.”);}注:synchronized类方法采用类对象锁(即当前类的类对象)去做线程的共享互斥。如上述示例中,采用类.class(继承自java.lang.Class)作为锁。2、synchronized声明Java示例:public void deposit(int m) { synchronized (this) { System.out.print(“This is synchronized statement with this lock.”); } synchronized (Something.class) { System.out.print(“This is synchronized statement with class lock.”); }}注:synchronized声明可以采用任意锁,上述示例中,分别采用了对象锁(this)和类锁(something.class)2.4 中断java.lang.Thread类有一个interrupt方法,该方法直接对线程调用。当被interrupt的线程正在sleep或wait时,会抛出InterruptedException异常。事实上,interrupt方法只是改变目标线程的中断状态(interrupt status),而那些会抛出InterruptedException异常的方法,如wait、sleep、join等,都是在方法内部不断地检查中断状态的值。interrupt方法Thread实例方法:必须由其它线程获取被调用线程的实例后,进行调用。实际上,只是改变了被调用线程的内部中断状态;Thread.interrupted方法Thread类方法:必须在当前执行线程内调用,该方法返回当前线程的内部中断状态,然后清除中断状态(置为false) ;isInterrupted方法Thread实例方法:用来检查指定线程的中断状态。当线程为中断状态时,会返回true;否则返回false。2.5 协调1、wait set / wait方法wait set是一个虚拟的概念,每个Java类的实例都有一个wait set,当对象执行wait方法时,当前线程就会暂停,并进入该对象的wait set。当发生以下事件时,线程才会退出wait set:①有其它线程以notify方法唤醒该线程②有其它线程以notifyAll方法唤醒该线程③有其它线程以interrupt方法唤醒该线程④wait方法已到期注:当前线程若要执行obj.wait(),则必须先获取该对象锁。当线程进入wait set后,就已经释放了该对象锁。下图中线程A先获得对象锁,然后调用wait()方法(此时线程B无法获取锁,只能等待)。当线程A调用完wait()方法进入wait set后会自动释放锁,线程B获得锁。2、notify方法notify方法相当于从wait set中从挑出一个线程并唤醒。下图中线程A在当前实例对象的wait set中等待,此时线程B必须拿到同一实例的对象锁,才能调用notify方法唤醒wait set中的任意一个线程。注:线程B调用notify方法后,并不会立即释放锁,会有一段时间差。3、notifyAll方法notifyAll方法相当于将wait set中的所有线程都唤醒。4、总结wait、notify、notifyAll这三个方法都是java.lang.Object类的方法(注意,不是Thread类的方法)。若线程没有拿到当前对象锁就直接调用对象的这些方法,都会抛出java.lang.IllegalMonitorStateException异常。obj.wait()是把当前线程放到obj的wait set;obj.notify()是从obj的wait set里唤醒1个线程;obj.notifyAll()是唤醒所有在obj的wait set里的线程。三、线程的状态转移当创建一个Thread子类或实现Runnable接口类的实例时,线程进入【初始】状态;调用实例的start方法后,线程进入【可执行】状态;系统会在某一时刻自动调度处于【可执行】状态的线程,被调度的线程会调用run方法,进入【执行中】状态;线程执行完run方法后,进入【结束】状态;处于【结束】状态的线程,在某一时刻,会被JVM垃圾回收;处于【执行中】状态的线程,若调用了Thread.yield方法,会回到【可执行】状态,等待再次被调度;处于【执行中】状态的线程,若调用了wait方法,会进入wait set并一直等待,直到被其它线程通过notify、notifyAll、interrupt方法唤醒;处于【执行中】状态的线程,若调用了Thread.sleep方法,会进入【Sleep】状态,无法继续向下执行。当sleep时间结束或被interrupt时,会回到【可执行状态】;处于

    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

    【执行中】状态的线程,若遇到阻塞I/O操作,也会停止等待I/O完成,然后回到【可执行状态】;<1>

    展开全文
  • Redis 是单线程的正确理解

    千次阅读 2022-01-18 16:14:17
    一、为什么Redis是单线程的 1️⃣官方答案 因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈。Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地...

    一、为什么Redis是单线程的

    1️⃣官方答案
    因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈。Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。

    2️⃣性能指标
    关于 Redis 的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。

    3️⃣详细原因

    1. 不需要各种锁的性能消耗
      Redis 的数据结构并不全是简单的 Key-Value,还有 list,hash 等复杂的结构。这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在 hash 当中添加或者删除一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。
      总之,在单线程的情况下,代码更清晰,处理逻辑更简单,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗,不存在多进程或者多线程导致的切换而消耗 CPU。
    2. 单线程多进程集群方案
      单线程的威力实际上非常强大,每核效率也非常高。多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。所以单线程、多进程的集群不失为一个时髦的解决方案。
    3. CPU 消耗
      采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。但是如果 CPU 成为 Redis 瓶颈,或者不想让服务器其他 CPU 核闲置,那怎么办?
      可以考虑多起几个 Redis 进程,Redis 是 key-value 数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些 key 放在哪个 Redis 进程上就可以了。

    二、Redis的单线程理解

    Redis 客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于 Redis 是单线程来处理命令的,所有到达服务端的命令都不会立刻执行,所有的命令都会进入一个队列中,然后逐个执行,并且多个客户端发送的命令的执行顺序是不确定的,但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是 Redis 的单线程基本模型。

    Redis 服务器通过 socket (套接字)与客户端或其他 Redis 服务器进行连接,而文件事件就是服务器对 socket 操作的抽象。服务器与客户端或其他服务器的通信会产生相应的文件事件,而服务器通过监听并处理这些事件来完成一系列网络通信操作。

    Redis 基于 Reactor 模式开发了自己的网络事件处理器——文件事件处理器,文件事件处理器使用 I/O 多路复用程序来同时监听多个 socket,并根据 socket 目前执行的任务来为 socket 关联不同的事件处理器。当被监听的 socket 准备好执行连接应答、读取、写入、关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用 socket 之前已关联好的事件处理器来处理这些事件。

    文件事件处理器的构成:

    注意:其中 I/O 多路复用程序通过队列向文件事件分派器传送 socket。

    I/O多路复用技术

    Redis 采用网络 I/O 多路复用技术,来保证在多连接的时候系统的高吞吐量。关于 I/O 多路复用(又被称为“事件驱动”),首先要理解的是,操作系统为你提供了一个功能,当你的某个 socket 可读或者可写的时候,它可以给你一个通知。这样当配合非阻塞的 socket 使用时,只有当系统通知我哪个描述符可读了,我才去执行 read 操作,可以保证每次 read 都能读到有效数据而不做纯返回 -1 和 EAGAIN 的无用功,写操作类似。

    操作系统的这个功能是通过 select/poll/epoll/kqueue 之类的系统调用函数来实现,这些函数都可以同时监视多个描述符的读写就绪状况,这样,多个描述符的 I/O 操作都能在一个线程内并发交替地顺序完成,这就叫 I/O 多路复用。多路—指的是多个 socket 连接,复用—指的是复用同一个 Redis 处理线程。多路复用主要有三种技术:select,poll,epoll。epoll 是最新的也是目前最好的多路复用技术。

    采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 I/O 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响 Redis 性能的瓶颈,基于这两点 Redis 具有很高的吞吐量。

    三、单线程的Redis为何高并发快

    Redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。

    1️⃣Redis 的高并发和快速原因

    1. Redis 是基于内存的,内存的读写速度非常快。
    2. Redis 是单线程的,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
    3. Redis 使用多路复用技术,可以处理并发的连接。非阻塞 IO 部实现采用 epoll,采用了 epoll+自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 IO 上浪费一点时间。
    4. 数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的。
    5. Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

    2️⃣单进程单线程弊端
    无法发挥多核 CPU 性能,不过可以通过在单机开多个 Redis 实例来完善。

    3️⃣Redis高并发总结

    1. Redis 是纯内存数据库,一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在 IO 上,所以读取速度快。
    2. 再说一下 IO,Redis 使用的是非阻塞 IO,IO 多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。
    3. Redis 采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。
    4. 另外,数据结构也帮了不少忙,Redis 全程使用 hash 结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。
    5. 还有一点,Redis 采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。

    四、常见疑问解答

    1️⃣为什么不采用多进程或多线程处理?

    ①多线程处理可能涉及到锁。
    ②多线程处理会涉及到线程切换而消耗 CPU。

    2️⃣单线程处理的缺点?

    ①耗时的命令会导致并发的下降,不只是读并发,写并发也会下降。
    ②无法发挥多核 CPU 性能,不过可以通过在单机开多个 Redis 实例来完善。

    3️⃣Redis 不存在线程安全问题?

    Redis 采用了线程封闭的方式,把任务封闭在一个线程,自然避免了线程安全问题,不过对于需要依赖多个 Redis 操作(即多个 Redis 操作命令)的复合操作来说,依然需要锁,而且有可能是分布式锁

    展开全文
  • Redis 到底是单线程还是多线程?

    千次阅读 2021-11-16 21:18:35
    1 Redis单线程问题 主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的...

    1 Redis单线程问题

    主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。
    在这里插入图片描述
    但Redis的其他功能,比如持久化、异步删除、集群数据同步等等,其实是由额外的线程执行的。Redis工作线程是单线程的,但是,整个Redis来说,是多线程的。

    2 Redis单线程为什么快

    (1) 基于内存操作:Redis 的所有数据都存在内存中,因此所有的运算都是内存级别的,所以他的性能比较高;
    (2) 数据结构简单:Redis 的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度都是 O(1),因此性能比较高;
    (3) 多路复用和非阻塞 I/O:Redis使用 I/O多路复用功能来监听多个 socket连接客户端,这样就可以使用一个线程连接来处理多个请求,减少线程切换带来的开销,同时也避免了 I/O 阻塞操作;
    (4) 避免上下文切换:因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生;

    3 I/O 多路复用

    这是IO模型的一种,即经典的Reactor设计模式,
    I/O 多路复用,简单来说就是通过监测文件的读写事件再通知线程执行相关操作,保证 Redis 的非阻塞 I/O 能够顺利执行完成的机制。
    多路指的是多个socket连接,
    复用指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。
    epoll是最新的也是目前最好的多路复用技术。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

    4 Redis 6

    在 Redis 6.0 中新增了多线程的功能来提高 I/O 的读写性能,他的主要实现思路是将主线程的 IO 读写任务拆分给一组独立的线程去执行,这样就可以使多个 socket 的读写可以并行化了,采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),将最耗时的Socket的读取、请求解析、写入单独外包出去,剩下的命令执行仍然由主线程串行执行并和内存的数据交互。
    在这里插入图片描述
    结合上图可知,网络IO操作就变成多线程化了,其他核心部分仍然是线程安全的,是个不错的折中办法。

    5 Redis6 开启多线程

    在Redis6.0中,多线程机制默认是关闭的,如果需要使用多线程功能,需要在redis.conf中完成两个设置。
    在这里插入图片描述
    1 设置io-thread-do-reads配置项为yes,表示启动多线程。
    2 设置线程个数。关于线程数的设置,官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3,如果为 8 核 CPU 建议线程数设置为 6,线程数一定要小于机器核数,线程数并不是越大越好。

    展开全文
  • 多线程实例,采用CreateThread函数。...(1) 该程序还将和单线程做对比。 (2) 由于给线程的函数传递了多个参数,所以采用结构体的方式传递参数。 (3) 为了演示效果,采用了比较耗时的打点处理。
  • node是多线程还是单线程

    千次阅读 2020-12-22 20:32:57
    node是单线程的,采用单线程异步非阻塞模式。因为javascript引擎的关系,node默认是单线程,一个node.js应用无法利用多核资源。Node.js采用事件驱动和异步I/O的方式,实现了一个单线程、高并发的运行时环境,而...
  • redis是单线程还是多线程?

    千次阅读 2022-02-07 14:36:16
    Redis 是单线程,主要是指 Redis 对外提供键值存储服务的主要流程,即网络 IO 和键值对读写是由⼀个线程来完成的。除此外 Redis 的其他功能,比如持久化、 异步删除、集群数据同步等,是由额外的线程执⾏的。在这...
  • Redis单线程模型

    千次阅读 2019-09-18 21:58:16
    1.Redis单线程模型 1.1.文件事件处理器 1>.Redis基于Reactor模式开发了网络事件处理器,这个处理器就叫做文件事件处理器(file event handler).这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,文件事件...
  • redis多线程,io多路复用技术,删除清理操作异步线程,网络io读写多线程
  • Redis是目前广为人知的一个内存数据库,在各个场景中都有着非常丰富的应用,前段时间Redis推出了6.0的版本,在新版本中采用了多线程模型。 因为我们公司使用的内存数据库是自研的,按理说我对Redis的关注其实并不算...
  • python是单线程的,多线程有意义么

    千次阅读 2020-10-09 17:29:38
    经常遇到小伙伴提到python是单线程的,写代码的时候用多线程没有意义,今天与大家分享一下关于python的单线程与多线程相关理解。 首先 python是单线程的 这句话是不对的。 这里要提到一个概念:Python的全局解释器锁...
  • Redis到底是单线程还是多线程?

    千次阅读 2020-05-18 15:28:54
    Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。这个数据不比采用单进程多线程的同样基于内存的 KV 数据库 Memcached 差!...
  • 为什么说Redis是单线程的以及Redis为什么这么快!

    万次阅读 多人点赞 2018-03-07 17:39:56
    既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)。 可以参考: https://redis.io/topics/faq 看到这里,你可能会气哭!本以为会有什么重大的技术...
  • Redis单线程为何这么快

    千次阅读 2022-02-08 10:03:48
    因为redis是基于Reactor模式开发了网络事件处理器和文件事件处理器,它是单线程的,所以redis才叫单线程模型。 Redis的单线程模型 文件处理器的结构包含:多个socket、IO多路复用程序、文件事件分派器和事件处理器...
  • 为什么Redis是单线程的?

    千次阅读 2021-11-08 00:46:10
    既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。 redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为多线程的本质就是 CPU 模拟出来多个...
  • Java单线程与多线程

    千次阅读 2019-03-08 18:17:52
    在我们了解单线程和多线程之前,我们必须搞清楚什么是进程。 一个运行起来的程序就是一个进程! 那程序又是什么呢? 对程序的通俗定义就是:一段可执行的代码。 当我们执行一段Java程序时,就在java虚拟机(JVM)中...
  • 彻底理解js是单线程

    千次阅读 多人点赞 2020-04-29 13:28:37
    JS执行是单线程 单线程是指Js引擎执行Js时只分了一个线程给他执行,也就是执行js时是单线程的。 那么问题来了,什么是线程?进程又是什么? 在分析浏览器的渲染过程之前,我们先了解一下什么是进程和线程: (1)...
  • Redis 单线程还是多线程?

    千次阅读 2019-09-18 09:51:27
    Redis 单线程还是多线程 前段时间无意间看到一篇博客,讲述了Redis6即将在年底发布的事情,好奇心驱动下搜索了官网,想看看新版Redis带来了什么新的功能,果然得到证实Redis在年底将发布新的版本:6.0,并且Redis...
  • 易语言的模块可以封装成程序集的模块,或者类模块,从大漠的角度,我们可以封装成单线程的模块和多线程的模块。 类模块 集模块 免注册 免查杀模块 多线程模块 创建调用 模块方法名称 视频源码链接 类模块集...
  • Redis是单线程还是多线程问题

    千次阅读 2020-08-08 11:52:47
    Redis是单线程还是多线程问题 在学习redis的过程中,很多文章都说redis是单线程,但在官方给出的说明中显示,redis6.0已经引入了多线程,对此我找了许多文档,将学习过程整理记录下来。 1、Redis单线程 在一开始的...
  • SpringBoot使用@scheduled定时执行任务的时候是在一个单线程中,如果有多个任务,其中一个任务执行时间过长,则有可能会导致其他后续任务被阻塞直到该任务执行完成。也就是会造成一些任务无法定时执行的错觉。 可以...
  • 单线程与多线程的区别?

    万次阅读 2018-08-29 16:58:35
    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序中包含多个执行流,即在一个程序中可以同时...
  • 单线程与多线程的区别

    万次阅读 多人点赞 2017-11-27 11:03:18
    什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。...线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区
  • JavaScript是单线程还是多线程?

    千次阅读 2020-07-08 18:32:55
    JavaScript单线程异步讲解
  • 关于I/O模型 ...对于线程,单线程情况下由一条线程负责所有客户端连接的I/O操作,而多线程情况下则由若干线程共同处理所有客户端连接的I/O操作。 此外,需要注意的是计算机的I/O其实包含了各种各样的I/
  • 文章目录单 Reactor 单线程工作原理示意图方案说明方案优缺点分析优点缺点使用场景单 Reactor 多线程工作原理示意图方案说明方案优缺点分析优点缺点主从 Reactor 多线程工作原理示意图方案说明方案优缺点分析优点...
  • springboot定时任务(单线程和多线程)

    千次阅读 2020-11-25 15:47:59
    而定时任务默认为单线程的,我们可以用多条线程取执行多个任务 设置线程池 (注意启动类上要加@EnableScheduling) @Configuration public class ScheduledConfig implements SchedulingConfigurer { @Override ...
  • 单线程一定是线程安全的吗

    千次阅读 2019-05-17 12:58:31
    单线程一定是线程安全的吗 单线程一定是线程安全的,因为我们常说的线程安全就是线程同步,也就是指多线程同时访问同一全局变量才会出现的问题,需要考虑线程同步。但是单线程不涉及到此类问题。 多线程的线程同步的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,193,326
精华内容 477,330
关键字:

单线程