多线程没有内存隔离,单个线程崩溃无效?

在现代计算机系统中,Cache的设计对整体性能有着重要的影响。同时多线程体系中,多个线程的资源共享产生了Cache冲突问题,为了保证处理器的吞吐率,要设计一个合理的Cache结构,并进行Cache的参数进行优化的配置。本文描述了超长指令字处理器中Cache的结构,主要包括Cache的映射方法和管理方法,并利用空间压缩技术提高了Cache的容量和利用率,利用Cache的参数配置方法减少能量的消耗。

  • 阻塞非阻塞:请求端行为

  • QPS:对服务端的请求量

    TPS: 服务端对请求的处理量(吞吐量)

    注:虽然请求,但不一定能全处理

  • “多线程”可以作为处理“高并发”状态的一执行方案

  • 并行比例增大,程序执行加快,体现在程序的单体运行时间越短,但不意味着能同时处理更多的程序


  • 被各线程共享的进程资源;

    线程合作,多线程并发并行工作

  • 线程间共享:执行的进程代码片段

    线程间独有:线程的堆栈

  • 创建进程:将代码实例化的过程


  • 多线程还可以提高资源的利用率。


  • 多线程还可以提高资源的利用率。

  • 多线程不是高并发,多线程是一种解决方式,是用来解决高并发产生的线程安全问题。
  • 并发的第一种概念就是“程序运行时的并发”,第二种概念是“程序具有并发性的性质”。

    只有多核CPU才能做到并行 + 并发,单核CPU只能并发。

  • 运行main函数时候,JVM启动的各个线程的作用

    • 为什么任务管理器中显式的线程数比创建的线程数多?

      • 即使代码不显式地创建线程,在运行main函数时,JVM也会启动其他的线程

  • 单核CPU上运行多线程程序有意义吗?

    1、首先可能我们一开始并不知道程序会运行在单核或者多核系统上

    2、多线程运行在单核CPU上,可以提升CPU的利用率,比如一个线程在进行IO操作等待的时候,另外一个线程接着做其他的事情,这样就不会造成卡顿、运行慢等问题

  • 高并发和多线程 的关系?

    高并发是一种状态,多线程是应对高并发的其中一种解决方案,高并发其实分很多场景,例如数据高并发,就可以通过添加缓存层来实现,比如redis

  • 同一时间有多个请求到服务器系统,服务器并行处理

  • 1、多个线程在同一时间段内启动、运行,注意是同一时间段,不是同一时间

    2、对并发性的简称,什么叫并发性,就是不同的部分可以无序或者同时执行,且不影响最终的执行结果,是一种描述性的表达,基于这个概念,并行和并发就不在一个维度上。

  • jvm启动的时候自动创建的线程

    • 服务器平均请求等待时间

  • redis 可以用来应对高并发.

  • "高并发"的意思是: 很多请求同时发送给服务器.

    然后服务器进行"并行"处理

  • 操作系统层面管理程序的多核cpu资源分配.

在学习了 Python 并发编程的一种实现——多线程。本博客继续学习 Python 并发编程的另一种实现方式——Asyncio。

在处理 I/O 操作时,使用多线程与普通的单线程相比,效率得到了极大的提高。多线程有诸多优点且应用广泛,但也存在一定的局限性:

  1. 比如,多线程运行过程容易被打断,因此有可能出现 race condition 的情况;
  2. 再如,线程切换本身存在一定的损耗,线程数不能无限增加,因此,如果 I/O 操作非常 heavy,多线程很有可能满足不了高效率、高质量的需求。

正是为了解决这些问题,Asyncio 应运而生。

首先来区分一下 Sync(同步)和 Async(异步)的概念。

  1. 所谓 Sync是指操作一个接一个地执行,下一个操作必须等上一个操作完成后才能执行
  2. Async指不同操作间可以相互交替执行,如果其中的某个操作被 block 了,程序并不会等待,而是会找出可执行的操作继续执行

对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:

同步:当进程执行IO(等待外部数据)的时候,-----等。同步(例如打电话的时候必须等)

异步:当进程执行IO(等待外部数据)的时候,-----不等,去执行其他任务,一直等到数据接收成功,再回来处理。异步(例如发短信)

事实上,Asyncio 和其他 Python 程序一样,是单线程的,它只有一个主线程,但是可以进行多个不同的任务(task),这里的任务,就是特殊的 future 对象。这些不同的任务,被一个叫做 event loop 的对象所控制。你可以把这里的任务,类比成多线程版本里的多个线程。

我们可以假设任务只有两个状态:一是预备状态;二是等待状态。所谓的预备状态,是指任务目前空闲,但随时待命准备运行。而等待状态,是指任务已经运行,但正在等待外部的操作完成,比如 I/O 操作。

在这种情况下,event loop 会维护两个任务列表,分别对应这两种状态;并且选取预备状态的一个任务(具体选取哪个任务,和其等待的时间长短、占用的资源等等相关),使其运行,一直到这个任务把控制权交还给 event loop 为止。

当任务把控制权交还给 event loop 时,event loop 会根据其是否完成,把任务放到预备或等待状态的列表,然后遍历等待状态列表的任务,查看他们是否完成。

  1. 如果完成,则将其放到预备状态的列表;
  2. 如果未完成,则继续放在等待状态的列表。

而原先在预备状态列表的任务位置仍旧不变,因为它们还未运行。

这样,当所有任务被重新放置在合适的列表后,新一轮的循环又开始了:event loop 继续从预备状态的列表中选取一个任务使其执行…如此周而复始,直到所有任务完成。

值得一提的是,对于 Asyncio 来说,它的任务在运行时不会被外部的一些因素打断,因此 Asyncio 内的操作不会出现 race condition 的情况,这样就不需要担心线程安全的问题了。

上面是Asyncio 的原理,我们结合具体的代码来看一下它的用法。


这里的 Async 和 await 关键字是 Asyncio 的最新写法,表示这个语句 / 函数是 non-block 的,正好对应前面所讲的 event loop 的概念。如果任务执行的过程需要等待,则将其放入等待状态的列表中,然后继续执行预备状态列表里的任务。

这里的asyncio.create_task(coro),表示对输入的协程 coro 创建一个任务,安排它的执行,并返回此任务对象。这个函数也是 Python 3.7+ 新增的,如果是之前的版本,你可以用asyncio.ensure_future(coro)等效替代。可以看到,这里我们对每一个网站的下载,都创建了一个对应的任务。

运行时间为4.3,相对于多线程提高了一倍。

实际工作中,想用好 Asyncio,特别是发挥其强大的功能,很多情况下必须得有相应的 Python 库支持。在多线程编程中,使用的是 requests 库,但本博客没有使用,而是用了 aiohttp 库,原因就是 requests 库并不兼容 Asyncio,但是 aiohttp 库兼容

Asyncio 软件库的兼容性问题,在 Python3 的早期一直是个大问题,但是随着技术的发展,这个问题正逐步得到解决。

另外,使用 Asyncio 时,因为在任务的调度方面有了更大的自主权,写代码时就得更加注意,不然很容易出错。

遇到实际问题时,多线程和 Asyncio 到底如何选择呢?

总的来说,你可以遵循以下伪代码的规范:

  1. 如果是 I/O bound,并且 I/O 操作很慢,需要很多任务 / 线程协同实现,那么使用 Asyncio 更合适。
  2. 如果是 I/O bound,但是 I/O 操作很快,只需要有限数量的任务 / 线程,那么使用多线程就可以了。
  3. 如果是 CPU bound,则需要使用多进程来提高程序运行效率。

关于多线程和多进程的使用场景:

  1. CPU密集型任务用多进程

如果你想对 CPU 密集型任务加速,使用多线程是无效的,请使用多进程。这里所谓的 CPU 密集型任务,是指会消耗大量 CPU 资源的任务,比如求 1 到 的乘积,或者是把一段很长的文字编码后又解码等等。

使用多线程之所以无效,原因正,Python 多线程的本质是多个线程互相切换,但同一时刻仍然只允许一个线程运行。因此,你使用多线程,和使用一个主线程,本质上来说并没有什么差别;反而在很多情况下,因为线程切换带来额外损耗,还会降低程序的效率。

而如果使用多进程,就可以允许多个进程之间 in parallel 地执行任务,所以能够有效提高程序的运行效率。

  1. IO密集型任务用多线程

至于 I/O 密集型任务,如果想要加速,请优先使用多线程或 Asyncio。当然,使用多进程也可以达到目的,但是完全没有这个必要。因为对 I/O 密集型任务来说,大多数时间都浪费在了 I/O 等待上。因此,在一个线程 / 任务等待 I/O 时,我们只需要切换线程 / 任务去执行其他 I/O 操作就可以了。

不过,如果 I/O 操作非常多、非常 heavy,需要建立的连接也比较多时,我们一般会选择 Asyncio。因为 Asyncio 的任务切换更加轻量化,并且它能启动的任务数也远比多线程启动的线程数要多。当然,如果 I/O 的操作不是那么的 heavy,那么使用多线程也就足够了。

  1. 不同于多线程,Asyncio 是单线程的,但其内部 event loop 的机制,可以让它并发地运行多个不同的任务,并且比多线程享有更大的自主控制权。
  2. Asyncio 中的任务,在运行过程中不会被打断,因此不会出现 race condition 的情况。尤其是在 I/O 操作 heavy 的场景下,Asyncio 比多线程的运行效率更高。因为 Asyncio 内部任务切换的损耗,远比线程切换的损耗要小;并且 Asyncio 可以开启的任务数量,也比多线程中的线程数量多得多。
  3. 但需要注意的是,很多情况下,使用 Asyncio 需要特定第三方库的支持,比如前面示例中的 aiohttp。而如果 I/O 操作很快,并不 heavy,那么运用多线程,也能很有效地解决问题。

《Python核心技术与实战》

我要回帖

更多关于 多线程没有内存隔离,单个线程崩溃 的文章

 

随机推荐