1.1异步相关概念:初步了解-创新互联

1.进程和线程的概念

计算机有5大基本组成部分,运算器,控制器,存储器,输入和输出。运算器和控制器封装到一起,加上寄存器组和cpu内部总线构成中央处理器(CPU)。cpu的根本任务,就是执行指令,对计算机来说,都是0,1组成的序列,cpu从逻辑上可以划分为3个模块:控制单元、运算单元和存储单元。这三个部分由cpu总线连接起来。

创新互联公司专注于网站建设|成都网站维护|优化|托管以及网络推广,积累了大量的网站设计与制作经验,为许多企业提供了网站定制设计服务,案例作品覆盖成都混凝土搅拌站等行业。能根据企业所处的行业与销售的产品,结合品牌形象的塑造,量身制作品质网站。

在这里插入图片描述
CPU的运行原理就是:控制单元在时序脉冲的作用下,将指令计数器里所指向的指令地址(这个地址是在内存里的)送到地址总线上去,然后CPU将这个地址里的指令读到指令寄存器进行译码。对于执行指令过程中所需要用到的数据,会将数据地址也送到地址总线,然后CPU把数据读到CPU的内部存储单元(就是内部寄存器)暂存起来,最后命令运算单元对数据进行处理加工。周而复始,一直这样执行下去。

2.并发和并行

并发:并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

并发与并行的区别:

  • 并发不是同时发生,并行是同时发生。 并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。
  • 并发是指一个处理器同时处理多个任务。并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
  • 并发是在同一个cpu上同时(不是真正的同时,而是看来是同时,因为CPU要在多个程序之间切换)运行多个程序。
  • 并行是每一个CPU运行一个程序。
3.多核、多CPU、CPU与多线程、多进程的关系
  • 进程是资源分配的最小单位,一个程序有至少一个进程。线程是程序执行的最小单位。一个进程有至少一个线程。
  • 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
  • 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
  • 多cpu的运行,对应进程的运行状态;多核cpu的运行,对应线程的运行状态。
  • 单CPU中进程只能是并发,多CPU计算机中进程可以并行。
  • 单CPU单核中线程只能并发,单CPU多核中线程可以并行。
  • 一个进程中可以有多条执行路径同时执行,一个线程就是进程中的一条执行路径。
4.多进程(multi-processing) 和多线程(multi-threading)的区别

多进程是各个并行任务之间“不使用“共同的内存空间;而多线程的各个并行任务”使用“共同的内存空间。

(1)多进程
  • 优点:独立内存空间;实现代码直观简单;充分利用多核多CPU;避免全局解释器锁的限制;
  • 缺点:无法实现对象和内容共享;需要较大的内存空间。
  • 应用:一般用于数学计算、数据处理等场景,计算密集型(CPU密集型)任务指的是需要做大量的逻辑运算。
(2) 多线程
  • 优点:轻量,需要的额外内存较小;共享内存,方便访问;对于CPython解释器,可以通过全局解释器锁使用C扩展;适合I/O密集型任务。
  • 缺点:全局解释器锁的限制;并行任务不能杀掉;实现代码较为复杂。
  • 一般用于爬虫请求、文件读写等场景。IO密集型任务指的是输入输出型。
(3)实现方式
  • 实现多线程的方式:threading.Thread()、线程池concurrent.futures.ThreadPoolExecutor
  • 实现多进程的方式:multiprocessing.Process、进程池concurrent.futures.ProcessPoolExecutor
(4)多线程与多进程的应用场景不一样:
  • 线程的创建开销小、由于GIL的存在,无法真正并行,适合GUI、网络通信、文件读写等IO密集型场景;
  • 进程的创建开销大,可以充分利用多个CPU实现并行,适合计算量比较大(比如单个函数执行需要几分钟、几十分钟以上),且无需IO(简单地说就是数据已经在内存中,不需要读取磁盘、不需要网络通信)的场景。
  • 多线程、多进程都不适合的场景:基本不涉及IO或只读取一次文件这种,且计算量不大,单线程短时间就能结束(一两秒左右)的情况下,单进程单线程是最好的。
5.python的全局解释器锁GIL

Python 全局解释器锁或GIL,简单来说,是一个互斥锁(或锁),它只允许一个线程控制 Python 解释器。这意味着在任何时间点都只能有一个线程处于执行状态。执行单线程程序的开发人员看不到 GIL 的影响,但它可能是 CPU 密集型和多线程代码中的性能瓶颈。由于即使在具有多个 CPU 内核的多线程架构中,GIL 也只允许一次执行一个线程,因此 GIL 被称为 Python 的“臭名昭著”的特性,但是它确实为Python内存处理提供了方便。

如果一个对象同时被多个线程来引用,那么引用计数可能同时增加或减少,每个线程按照自己的方式进行计数,对象在整个内存中的引用变得十分混乱,很容易造成内存泄漏或者其他很多不可预见的Bug。一个解决办法给就是每个线程都给引用计数加一个锁,阻止别人修改,不过这样会造成锁死现象(比如一个对象有多个锁时),另外,大量的资源会浪费在加锁解锁的过程了,严重拖慢了程序运行速度。

这个时候,就需要一个统一来管理引用计数的机制,以确保对象引用计数准确、安全。全局解释器锁就是用来处理这种情况的。它既避免了不同线程带来的引用计数混乱,又避免了过多线程锁带来的死锁和运行效率低的问题。虽然全局解释器锁解决了对象引用计数的问题,但随之而来的是,很多CPU密集型任务在全局解释器锁的作用下,实际上变成了单线程,不能充分发挥CPU的算力,影响程序速度。

全局解释器锁并不是Python独有的,其他一些语言,比如Ruby也存在全局解释器锁。还有一些语言没有使用引用计数的方式来管理内容,而是使用垃圾回收机制(GC)来管理内存。虽然这样避免了全局解释器锁,但是在单线程处理上,GC并不占有优势。

全局解释器锁对多线程的影响

  • 首先应该区分不同性质的任务,有一些是CPU密集型的任务,有一些是I/O密集型的任务。
    CPU密集型的任务在大程度上使用了CPU,比如数学矩阵的计算、图像处理、文件解压缩等。【一般使用多进程应对】
  • I/O密集型任务在需要花费很多时间来等待信息的输入和输出(读写),比如从网址下载内容,大量访问磁盘进行读写等。【一般使用多线程应对】
6.进程池

进程就是运行着的程序。写的python程序(或者其他应用程序比如画笔、qq等),运行起来,就称之为一个进程;在windows下面打开任务管理器,里面显示了当前系统上运行着的进程。这些程序还没有运行的时候,它们的程序代码文件存储在磁盘中,就是那些扩展名为 .exe 文件。双击它们,这些 .exe 文件就被os加载到内存中,运行起来,成为进程。

进程池:可以提供指定数量的进程给用户使用,即当有新的请求提交到进程池中时,如果池未满,则会创建一个新的进程用来执行该请求;反之,如果池中的进程数已经达到规定大值,那么该请求就会等待,只要池中有进程空闲下来,该请求就能得到执行。

7.线程池

系统中每个进程里面至少包含一个 线程 。线程是操作系统创建的,每个线程对应一个代码执行的数据结构,保存了代码执行过程中的重要的状态信息。没有线程,操作系统没法管理和维护 代码运行的状态信息。所以没有创建线程之前,操作系统是不会执行我们的代码的。

8.同步和异步
  • 同步,就是调用某个东西时,调用方得等待这个调用返回结果才能继续往后执行。
  • 异步,和同步相反调用方不会等待得到结果,而是在调用发出后调用者可用继续执行后续操作,被调用者通过状体来通知调用者,或者通过回掉函数来处理这个调用
9.队列(线程间通信)

在一个进程中,不同子线程负责不同的任务,t1子线程负责获取到数据,t2子线程负责把数据保存的本地,那么他们之间的通信使用Queue来完成。因为再一个进程中,数据变量是共享的,即多个子线程可以对同一个全局变量进行操作修改,Queue是加了锁的安全消息队列。

Python的Queue队列,主要用于多生产者和消费者模式下的队列实现,特别适合多线程时的消息交换。通过使用队列,把生产者和消费者分解开来,作为其中的中间件,比如生产者产生一个数据,然后放到queue队列中,queue队列在把这个数据放到消费者线程中。使用单线程不必用队列,但是队列对于多线程来说是不可或缺的。

10.线程同步

如果没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。同步就是协同步调,按预定的先后次序进行运行。

"同"字从字面上容易理解为一起动作,其实不是,"同"字应是指协同、协助、互相配合。如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。

实现线程同步的方式可以是:

  • 线程锁
  • 条件变量
  • 信号变量
  • 事件
11.生产者与消费者

生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者消耗数据或者资料。

举一个寄信的例子,假设要寄一封信,大致过程如下:

  1. 你把信写好-―相当于生产者制造数据;
  2. 把信放入邮简――相当于生产者把数据放入缓冲区;
  3. 递员把信从邮简取出—一相当于消费者把数据取出缓冲区;
  4. 递员把信拿去邮局做相应的处理――相当于消费者处理数据;
12.daemon和non-daemon线程

Python 中,构造线程的时候,可以设置daemon属性,这个属性必须再start()方法前设置好。线程daemon属性,如果设定就是用户的设置,否则就取当前线程的daemon值。主线程是non-daemon线程,即daemon = False。线程具有一个daemon属性,可以手动设置为True或者False,也可以不设置,则取默认值为None。

如果除主线程之外还有non-daemon线程的时候,主线程退出时,也不会杀掉所有daemon线程,直到所有non-daemon线程全部结束,如果还有daemon线程,主线程需要退出,会结束所有daemon线程,程序退出。

13.锁和共享内存

【多线程、多进程涉及读写必须要用锁,一定要用】

(1)多线程的线程锁

①死锁问题和解决
如果多个线程要调用多个现象,而A线程调用A锁占用了A对象,B线程调用了B锁占用了B对象,A线程不能调用B对象,B线程不能调用A对象,于是一直等待。这就造成了线程“死锁”。Threading模块中,也有一个类,RLock,称之为可重入锁。该锁对象内部维护着一个Lock和一个counter对象。counter对象记录了acquire的次数,使得资源可以被多次require。最后,当所有RLock被release后,其他线程才能获取资源。在同一个线程中,RLock.acquire可以被多次调用,利用该特性,可以解决部分死锁问题

②当多个线程同时访问一个数据时,需加锁,排队变成单线程一个一个执行,避免出错。
③加锁避免并发导致逻辑出错。

④每当一个线程a要访问共享数据时,必须先获得锁定;如果已经有别的线程b获得锁定了,那么就让线程a暂停,也就是同步阻塞;等到线程b访问完毕,释放锁以后,再让线程a继续。

⑤同一时刻只允许一个线程操作该数据,可以保证数据安全。 线程锁用于锁定资源,可以同时使用多个锁,当需要独占某一资源时,任何一个锁都可以锁这个资源。

⑥将一段代码锁住,一旦获得锁权限,除非释放线程锁,否则其他代码都无法获得锁权限。

(2)多进程的进程锁

①很多时候,需要在多个进程中同时写一个文件,如果不加锁机制,就会导致写文件错乱。
②谁先抢到锁谁先执行,等到该进程执行完成后,其它进程再抢锁执行。
③python多进程编程使用进程池非常的方便管理进程,但是有时候子进程之间会抢占一些独占资源,比如consol或者比如日志文件的写入权限,这样的时候我们一般需要共享一个Lock来对独占资源加锁。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧

网站题目:1.1异步相关概念:初步了解-创新互联
转载来源:https://www.cdcxhl.com/article38/eehsp.html

成都网站建设公司_创新互联,为您提供自适应网站搜索引擎优化定制开发网站设计静态网站服务器托管

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

外贸网站制作