精华内容
下载资源
问答
  • 下面从程序的顺序执行、程序的执行环境和程序的并发执行几方面介绍多道程序设计模型。 一、程序的顺序执行 程序是一个时间上按严格次序前后相继的操作序列,这些操作是机器指令或高级语言编写的语句。人们习惯的...

    采用多道程序设计可以提高处理器的利用率。多道程序设计技术充分发挥了处理器与外围设备以及外围设备之间的并行工作能力,从而提高处理器和其他各种资源的利用率。下面从程序的顺序执行、程序的执行环境和程序的并发执行几方面介绍多道程序设计模型。

    一、程序的顺序执行

    程序是一个在时间上按严格次序前后相继的操作序列,这些操作是机器指令或高级语言编写的语句。人们习惯的传统程序设计方法是顺序程序设计,计算机也是以顺序方式工作的:处理器一次执行一条指令,对内存一次访问一个字节或字,对处部设备一次传送一个数据块。顺序处理也是人们习惯的思考方法,为了解决一个复杂的问题,人们把它分解成一些较为简单、易于分析的小问题,然后逐个解决。也可以把一个复杂的程序划分为若干个程序段,然后按照某种次序逐个执行这些程序段。

    我们把一个具有独立功能的程序独占处理器直到得到最终结果的过程称为程序的顺序执行。程序的顺序执行具有如下特点。

    1.顺序性

    程序所规定的动作在机器上严格地按顺序执行。每个动作的执行都以前一个动作的结束为前提条件,即程序和机器执行它的活动严格一一对应。

    2.封闭性

    程序运行后,其计算结果只取决于程序自身,程序执行得到的最终结果由给定的初始条件决定,不受外界因素的影响。程序所使用的资源(包括处理器、内存、文件等)是专有的,这些资源的状态(除了初始状态外)只有程序本身的动作才能改变。

    3.程序执行结果的确定性

    也称为程序执行结果与时间无关性。程序执行的结果与它的执行速度无关,即处理器在执行程序时,任意两个动作之间的停顿对程序的计算结果都不会产生影响。

    4.程序执行结果的可再现性

    如果程序在不同的时间执行,只要输入的初始条件相同,则无论何时重复执行该程序都会得到相同的结果。

    程序的顺序性和封闭性是一切顺序程序所应具有的特性,从这两个特性出发,不难引出程序执行时所具有的另外两个特性。顺序程序与时间无关的特性,可使程序的编制者不必去关心不属于他控制的那些细节(如操作系统的调度算法和外部设备操作的精确时间等);顺序程序执行结果的可再现性,则对程序检测和校正程序的错误带来了方便。

    二、程序的并发执行

    所谓程序并发执行,是指两个或两个以上程序在计算机系统中,同时处于已开始执行且尚未结束的状态。能够参与并发执行的程序称为并发程序。程序的并发执行,可以充分利用系统的资源,提高计算机的处理能力。但是,程序的并发执行产生了一些和程序顺序执行时不同的特性。程序的并发执行有如下特征。

    1.在执行期间并发程序相互制约

    资源的共享和竞争存在于多道程序的并发执行中,从而制约了各道程序的执行速度。由于本来并无逻辑关系的程序之间产生了相互制约的关系,而各个程序活动的工作状态与所处环境有密切关系,使并发程序的执行出现了“执行——暂停——执行”的活动现象。

    2.程序与计算不再一一对应

    在并发执行中,允许多个用户进程调用一个共享程序段,从而形成了多个“计算”。如在分时系统中,一个编译程序往往同时为几个用户提供编译服务,该编译程序便对应了几个“计算”。

    3.并发程序的执行结果不可再现

    并发程序执行结果与其执行的相对速度以及并发执行的多道程序之间的相互关系有关,导致并发程序的执行结果不可再现,即执行结果是不确定的。

    4.程序的并行执行与程序的并发执行

    多道程序的并发执行是指它们在宏观上,即在某一段时间周期内是同时进行的(这个时间周期,比处理器的指令处理周期要长得多,但是从操作人员的感觉来看,仍然时一个瞬间)。但从微观上看,除了多处理器系统外,在单处理器系统中,这些程序仍然是顺序执行的。

    程序的并行执行与程序的并发执行,这两者存在着差别。前者是指不论从宏观的时间周期上看,还是从微观上看,若干程序确实在同时运行;而程序的并发执行,如果在单处理器系统中,它们在宏观上是同时进行的,但在微观上,这些程序仍然是顺序执行的

    展开全文
  • 多道程序设计出现解决了这个问题,就是把内存分为几个部分,每一个部分放不同程序。当一个程序需要等待I/O操作完成时。那么CPU可以切换执行内存中另外一个程序。如果内存中可以同时存放足够多程序,那CPU...

    多道程序设计的出现解决了这个问题,就是把内存分为几个部分,每一个部分放不同的程序。当一个程序需要等待I/O操作完成时。那么CPU可以切换执行内存中的另外一个程序。如果内存中可以同时存放足够多的程序,那CPU的利用率可以接近100%。 

    在这个时候,引入了第一个概念- 进程, 进程的本质是一个正在执行的程序,程序运行时系统会创建一个进程,并且给每个进程分配独立的内存地址空间保证每个进程地址不会相互干扰。同时,在CPU对进程做时间片的切换时,保证进程切换过程中仍然要从进程切换之前运行的位置出开始执行。所以进程通常还会包括程序计数器、堆栈指针。 

    有了进程以后,可以让操作系统从宏观层面实现多应用并发。而并发的实现是通过CPU时间片不端切换执行的。对于单核CPU来说,在任意一个时刻只会有一个进程在被CPU调度 

     

    展开全文
  • 程序:是指编译好二进制文件,存放磁盘上,并不占用系统资源(系统资源包括CPU、内存、打开文件、设备、锁…) 进程:是一个抽象概念,与操作系统原理密切相关。进程是活跃的程序,占用系统资源。内存中...

    程序和进程

    • 程序:是指编译好的二进制文件,存放在磁盘上,并不占用系统资源(系统资源包括CPU、内存、打开的文件、设备、锁…)
    • 进程:是一个抽象的概念,与操作系统原理密切相关。进程是活跃的程序,占用系统资源。在内存中执行。(程序运行起来之后,产生一个进程)。
    • 那么我们可以形象的将程序比作一个剧本,这个剧本就是一张一张的纸组成的,那么就是进程就要演的戏,一出戏上面包括舞台、演员、灯光、道具等等。同一个剧本可以在多个舞台上同时上演,同样的,同一个程序也可以加载为不同的进程(而且彼此之间互不影响)。
    • 举个例子,在linux终端上同时打开两个终端。他们各自都有一个bash但是彼此的ID却是不同的。

    二:并发的认识

    • 并发:在操作系统中,一个时间段中有多个进程都处于已经启动运行—到-----运行完毕之间的状态。但是呢,任一时刻点上CPU上只有一个进程在运行。
    • 举个例子,现在,我们使用计算机可以边听音乐边聊天边上网。那么我用自己的话来说,意思就是说CPU先运算音乐进程几纳秒,然后停下来在运算聊天几微秒,然后在停下来再运算上网几微秒,由于速度很快,我们肉眼几乎发现不了进程在切换着运行。

    单道程序设计

    • 所有进程一个一个排对执行。若A阻塞,B只能等待,即使CPU处于空闲状态。而在人机交互时阻塞的出现时必然的。所有这种模型在系统资源利用上极其不合理,在计算机发展历史上存在不久,大部分便被淘汰了。像以前的Dos就是单道程序设计系统。

    多道程序设计

    • 在计算机内存中同时存放几道相互独立的程序,它们在管理程序控制之下,相互穿插的运行。多道程序设计必须有硬件基础作为保证。
    • 时钟中断即为多道程序设计模型的理论基础。 并发时,任意进程在执行期间都不希望放弃cpu。因此系统需要一种强制让进程让出cpu资源的手段。时钟中断有硬件基础作为保障,对进程而言不可抗拒。 操作系统中的中断处理函数,来负责调度程序执行。
    • 在多道程序设计模型中,多个进程轮流使用CPU (分时复用CPU资源)。而当下常见CPU为纳秒级,1秒可以执行大约10亿条指令。由于人眼的反应速度是毫秒级,所以看似同时在运行。
    • 实质上,并发是宏观并行,微观串行!

    CPU

    • 中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。中央处理器主要包括运算器(算术逻辑运算单元,ALU,ArithmeTIc Logic Unit)和高速缓冲存储器(Cache)及实现它们之间联系的数据(Data)、控制及状态的总线(Bus)。它与内部存储器(Memory)和输入/输出(I/O)设备合称为电子计算机三大核心部件。
    • cpu的基本结构
        从功能上看,一般CPU的内部结构可分为:控制单元、逻辑运算单元、存储单元(包括内部总线和缓冲器)三大部分。其中控制单元完成数据处理整个过程中的调配工作,逻辑单元则完成各个指令以便得到程序最终想要的结果,存储单元就负责存储原始数据以及运算结果。浑然一体的配合使得CPU拥有了强大的功能,可以完成包括浮点、多媒体等指令在内的众多复杂运算,也为数字时代加入了更多的活力。
    1. 逻辑部件

    英文Logic components;运算逻辑部件。可以执行定点或浮点算术运算操作、移位操作以及逻辑操作,也可执行地址运算和转换。

    1. 寄存器

    寄存器部件,包括寄存器、专用寄存器和控制寄存器。 通用寄存器又可分定点数和浮点数两类,它们用来保存指令执行过程中临时存放的寄存器操作数和中间(或最终)的操作结果。 通用寄存器是中央处理器的重要部件之一。

    1. 控制部件

    英文Control unit;控制部件,主要是负责对指令译码,并且发出为完成每条指令所要执行的各个操作的控制信号。

    其结构有两种:一种是以微存储为核心的微程序控制方式;一种是以逻辑硬布线结构为主的控制方式。

    微存储中保持微码,每一个微码对应于一个最基本的微操作,又称微指令;各条指令是由不同序列的微码组成,这种微码序列构成微程序。中央处理器在对指令译码以后,即发出一定时序的控制信号,按给定序列的顺序以微周期为节拍执行由这些微码确定的若干个微操作,即可完成某条指令的执行。

    简单指令是由(3~5)个微操作组成,复杂指令则要由几十个微操作甚至几百个微操作组成。

    CPU的逻辑单元
    • 更细一点,从实现的功能方面看,CPU大致可分为如下八个逻辑单元:

    1. 指令高速缓存,俗称指令寄存器 : 它是芯片上的指令仓库,有了它CPU就不必停下来查找计算机内存中的指令,从而大幅提高了CPU的运算速度。

    2. 译码单元,俗称指令译码器 : 它负责将复杂的机器语言指令解译成运算逻辑单元(ALU)和寄存器能够理解的简单格式,就像一位外交官。

    3. 控制单元 : 既然指令可以存入CPU,而且有相应指令来完成运算前的准备工作,背后自然有一个扮演推动作用的角色——它便是负责整个处理过程的操作控制器。根据来自译码单元的指令,它会生成控制信号,告诉运算逻辑单元(ALU)和寄存器如何运算、对什么进行运算以及对结果进行怎样的处理。

    4. 寄存器 : 它对于CPU来说非常的重要,除了存放程序的部分指令,它还负责存储指针跳转信息以及循环操作命令,是运算逻辑单元(ALU)为完成控制单元请求的任务所使用的数据的小型存储区域,其数据来源可以是高速缓存、内存、控制单元中的任何一个。

    5. 逻辑运算单元(ALU) : 它是CPU芯片的智能部件,能够执行加、减、乘、除等各种命令。此外,它还知道如何读取逻辑命令,如或、与、非。来自控制单元的讯息将告诉运算逻辑单元应该做些什么,然后运算单元会从寄存器中间断或连续提取数据,完成最终的任务。

    6. 预取单元 : CPU效能发挥对其依赖非常明显,预取命中率的高低直接关系到CPU核心利用率的高低,进而带来指令执行速度上的不同。根据命令或要执行任务所提出的要求,何时时候,预取单元都有可能从指令高速缓存或计算机内存中获取数据和指令。当指令到达时,预取单元最重要的任务就是确保所有指令均排列正确,然后发送给译码单元。

    7. 总线单元 : 它就像一条高速公路,快速完成各个单元间的数据交换,也是数据从内存流进和流出CPU的地方。

    8. 数据高速缓存 : 存储来自译码单元专门标记的数据,以备逻辑运算单元使用,同时还准备了分配到计算机不同部分的最终结果。

    • 通过以上介绍可以看出CPU虽小,方寸之地却能容纳大世界,内部更像一个发达的装配工厂,环环相扣,层层相套。正因为有了相互间的协作配合,才使得指令最终得以执行,才构成了图文并茂、影像结合的神奇数字世界。
    cpu的工作原理:
    • 我们都知道CPU的根本任务就是执行指令,对计算机来说最终都是一串由“0”和“1”组成的序列。CPU从逻辑上可以划分成3个模块,分别是控制单元、运算单元和存储单元,这三部分由CPU内部总线连接起来。如下所示:
      在这里插入图片描述

      • 控制单元:控制单元是整个CPU的指挥控制中心,由指令寄存IR(InstrucTIon Register)、指令译码器ID(InstrucTIon Decoder)和操作控制器OC(OperaTIon Controller)等,对协调整个电脑有序工作极为重要。它根据用户预先编好的程序,依次从存储器中取出各条指令,放在指令寄存器IR中,通过指令译码(分析)确定应该进行什么操作,然后通过操作控制器OC,按确定的时序,向相应的部件发出微操作控制信号。操作控制器OC中主要包括节拍脉冲发生器、控制矩阵、时钟脉冲发生器、复位电路和启停电路等控制逻辑。

      • 运算单元:是运算器的核心。可以执行算术运算(包括加减乘数等基本运算及其附加运算)和逻辑运算(包括移位、逻辑测试或两个值比较)。相对控制单元而言,运算器接受控制单元的命令而进行动作,即运算单元所进行的全部操作都是由控制单元发出的控制信号来指挥的,所以它是执行部件。

    • 存储单元:包括CPU片内缓存和寄存器组,是CPU中暂时存放数据的地方,里面保存着那些等待处理的数据,或已经处理过的数据,CPU访问寄存器所用的时间要比访问内存的时间短。采用寄存器,可以减少CPU访问内存的次数,从而提高了CPU的工作速度。但因为受到芯片面积和集成度所限,寄存器组的容量不可能很大。寄存器组可分为专用寄存器和通用寄存器。专用寄存器的作用是固定的,分别寄存相应的数据。而通用寄存器用途广泛并可由程序员规定其用途,通用寄存器的数目因微处理器而异。这个是我们以后要介绍这个重点,这里先提一下。

    • 我们将上图细化一下,可以得出CPU的工作原理概括如下:
      在这里插入图片描述

    • 总结一下,CPU的运行原理就是:
        1. 取指令:CPU的控制器从内存读取一条指令并放入指令寄存器。指令的格式一般是这个样子滴:
      在这里插入图片描述

    操作码就是汇编语言里的mov,add,jmp等符号码;操作数地址说明该指令需要的操作数所在的地方,是在内存里还是在CPU的内部寄存器里。

    1. 指令译码:指令寄存器中的指令经过译码,决定该指令应进行何种操作(就是指令里的操作码)、操作数在哪里(操作数的地址)。

    2. 执行指令,分两个阶段“取操作数”和“进行运算”。

    3. 修改指令计数器,决定下一条指令的地址。
      在这里插入图片描述
      在这里插入图片描述

    • 如上图所示,存储介质中,从上到小,内存越来越大,价格越来越便宜,但是传输速率越来越慢。因此将他们搭配起来使用是最好的。
    • 假如数据在硬盘上放着,当我们执行某个程序的时候,从硬盘中先拿到内存中,在拿到cache缓存器中,然后由预取器预取指令,再交给译码器进行译码,译码器再交给ALU算术逻辑单元执行运算,然后,将运算好的数据交给寄存器,由寄存器交给内存,再由内存交给硬盘。

    MMU(内存管理单元)

    在这里插入图片描述

    • 我就简答的说一下关于MMU,MMU就是为了完成物理内存和虚拟内存之间的映射,还有修改内存的访问级别。
    • 在没有使用虚拟存储器的机器上,虚拟地址被直接送到内存总线上,使具有相同地址的物理存储器被读写。而在使用了虚拟存储器的情况下,虚拟地址不是被直接送到内存地址总线上,而是送到内存管理单元——MMU(主角终于出现了)。他由一个或一组芯片组成,一般存在与协处理器中,其功能是把虚拟地址映射为物理地址。
    MMU工作过程
    • 大多数使用虚拟存储器的系统都使用一种称为分页(paging)。虚拟地址空间划分成称为页(page)的单位,而相应的物理地址空间也被进行划分,单位是页框(frame).页和页框的大小必须相同。接下来配合图片我以一个例子说明页与页框之间在MMU的调度下是如何进行映射的:
      在这里插入图片描述

    • 在这个例子中我们有一台可以生成16位地址的机器,它的虚拟地址范围从0x0000~0xFFFF(64K),而这台机器只有32K的物理地址,因此他可以运行64K的程序,但该程序不能一次性调入内存运行。这台机器必须有一个达到可以存放64K程序的外部存储器(例如磁盘或是FLASH)以保证程序片段在需要时可以被调用。在这个例子中,页的大小为4K,页框大小与页相同(这点是必须保证的,内存和外围存储器之间的传输总是以页为单位的),对应64K的虚拟地址和32K的物理存储器,他们分别包含了16个页和8个页框。

    • 关于MMU,我后面再来介绍。

    展开全文
  • 一、线程背景进程 之前我们已经了解了操作系统中进程概念,程序并不能...在多道编程中,我们允许多个程序同时加载到内存中,操作系统调度下,可以实现并发执行。这是这样设计,大大提高了CPU利用率。...

    一、线程背景

    进程

      之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。有了进程为什么要有线程
      进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上:

    • 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
    • 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。

      如果这两个缺点理解比较困难的话,举个现实的例子也许你就清楚了:如果把我们上课的过程看成一个进程的话,那么我们要做的是耳朵听老师讲课,手上还要记笔记,脑子还要思考问题,这样才能高效的完成听课的任务。而如果只提供进程这个机制的话,上面这三件事将不能同时执行,同一时间只能做一件事,听的时候就不能记笔记,也不能用脑子思考,这是其一;如果老师在黑板上写演算过程,我们开始记笔记,而老师突然有一步推不下去了,阻塞住了,他在那边思考着,而我们呢,也不能干其他事,即使你想趁此时思考一下刚才没听懂的一个问题都不行,这是其二。
      现在你应该明白了进程的缺陷了,而解决的办法很简单,我们完全可以让听、写、思三个独立的过程,并行起来,这样很明显可以提高听课的效率。而实际的操作系统中,也同样引入了这种类似的机制——线程。线程的出现

      60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。

      因此在80年代,出现了能独立运行的基本单位——线程(Threads)

      注意:进程是资源分配的最小单位,线程是CPU调度的最小单位.

          每一个进程中至少有一个线程。 

    进程和线程的关系

    4f779742f6bd5d090f6d956c7ed7ec54.png

      线程与进程的区别可以归纳为以下4点:
      1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
      2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
      3)调度和切换:线程上下文切换比进程上下文切换要快得多。
      4)在多线程操作系统中,进程不是一个可执行的实体。

    线程的特点

      在多线程的操作系统中,通常是在一个进程中包括多个线程,每个线程都是作为利用CPU的基本单位,是花费最小开销的实体。线程具有以下属性。
      1)轻型实体
      线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。
      线程的实体包括程序、数据和TCB。线程是动态概念,它的动态特性由线程控制块
      2)独立调度和分派的基本单位。
      在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。由于线程很“轻”,故线程的切换非常迅速且开销小(在同一进程中的)。
      3)共享进程资源。  线程在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的进程id,这意味着,线程可以访问该进程的每一个内存资源;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
      4)可并发执行。
      在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有线程都能并发执行;同样,不同进程中的线程也能并发执行,充分利用和发挥了处理机与外围设备并行工作的能力。

    使用线程的实际场景

    3fae0e0790a989d29dd55e7e6ef22555.png

      开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。

    内存中的线程

    c23421f3626969eb3474793eaf68ecb9.png

      多个线程共享同一个进程的地址空间中的资源,是对一台计算机上多个进程的模拟,有时也称线程为轻量级的进程。

      而对一台计算机上多个进程,则共享物理内存、磁盘、打印机等其他物理资源。多线程的运行也多进程的运行类似,是cpu在多个线程之间的快速切换。

      不同的进程之间是充满敌意的,彼此是抢占、竞争cpu的关系,如果迅雷会和QQ抢资源。而同一个进程是由一个程序员的程序创建,所以同一进程内的线程是合作关系,一个线程可以访问另外一个线程的内存地址,大家都是共享的,一个线程干死了另外一个线程的内存,那纯属程序员脑子有问题。

      类似于进程,每个线程也有自己的堆栈,不同于进程,线程库无法利用时钟中断强制线程让出CPU,可以调用thread_yield运行线程自动放弃cpu,让另外一个线程运行。

      线程通常是有益的,但是带来了不小程序设计难度,线程的问题是:

      1. 父进程有多个线程,那么开启的子线程是否需要同样多的线程

      2. 在同一个进程中,如果一个线程关闭了文件,而另外一个线程正准备往该文件内写内容呢?

      因此,在多线程的代码中,需要更多的心思来设计程序的逻辑、保护程序的数据。

    二、开启线程的两种方式:

    # from multiprocessing import Process
    # from threading import Thread
    # import time
    #
    #
    # def task(name):
    #     print('%s is running'%name)
    #     time.sleep(1)
    #     print('%s is over'%name)
    #
    #
    # # 开启线程不需要在main下面执行代码 直接书写就可以
    # # 但是我们还是习惯性的将启动命令写在main下面
    # t = Thread(target=task,args=('egon',))
    # # p = Process(target=task,args=('jason',))
    # # p.start()
    # t.start()  # 创建线程的开销非常小 几乎是代码一执行线程就已经创建了
    # print('主')
    
    
    
    from threading import Thread
    import time
    
    class MyThead(Thread):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('%s is running'%self.name)
            time.sleep(1)
            print('egon DSB')
    
    
    if __name__ == '__main__':
        t = MyThead('egon')
        t.start()
        print('主')

    三、TCP服务端实现并发的效果

    import socket
    from threading import Thread
    from multiprocessing import Process
    """
    服务端
        1.要有固定的IP和PORT
        2.24小时不间断提供服务
        3.能够支持并发
        
    从现在开始要养成一个看源码的习惯
    我们前期要立志称为拷贝忍者 卡卡西 不需要有任何的创新
    等你拷贝到一定程度了 就可以开发自己的思想了
    """
    server =socket.socket()  # 括号内不加参数默认就是TCP协议
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    
    # 将服务的代码单独封装成一个函数
    def talk(conn):
        # 通信循环
        while True:
            try:
                data = conn.recv(1024)
                # 针对mac linux 客户端断开链接后
                if len(data) == 0: break
                print(data.decode('utf-8'))
                conn.send(data.upper())
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    
    # 链接循环
    while True:
        conn, addr = server.accept()  # 接客
        # 叫其他人来服务客户
        # t = Thread(target=talk,args=(conn,))
        t = Process(target=talk,args=(conn,))
        t.start()
    
    
    """客户端"""
    import socket
    
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    while True:
        client.send(b'hello world')
        data = client.recv(1024)
        print(data.decode('utf-8'))

    四:线程对象的join方法

    from threading import Thread
    import time
    
    
    def task(name):
        print('%s is running'%name)
        time.sleep(3)
        print('%s is over'%name)
    
    
    if __name__ == '__main__':
        t = Thread(target=task,args=('egon',))
        t.start()
        t.join()  # 主线程等待子线程运行结束再执行
        print('主')

    五:同一个进程下的多个线程数据是共享的

    from threading import Thread
    import time
    
    
    money = 100
    
    
    def task():
        global money
        money = 666
        print(money)
    
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
        t.join()
        print(money)

    六:线程对象属性及其他方法

    from threading import Thread, active_count, current_thread
    import os,time
    
    
    def task(n):
        # print('hello world',os.getpid())
        print('hello world',current_thread().name)
        time.sleep(n)
    
    
    if __name__ == '__main__':
        t = Thread(target=task,args=(1,))
        t1 = Thread(target=task,args=(2,))
        t.start()
        t1.start()
        t.join()
        print('主',active_count())  # 统计当前正在活跃的线程数
        # print('主',os.getpid())
        # print('主',current_thread().name)  # 获取线程名字

    七:守护线程

    def foo():
        print(123)
        time.sleep(1)
        print('end123')
    
    
    def func():
        print(456)
        time.sleep(3)
        print('end456')
    
    
    if __name__ == '__main__':
        t1 = Thread(target=foo)
        t2 = Thread(target=func)
        t1.daemon = True
        t1.start()
        t2.start()
        print('主.......')

    八:线程互斥锁

    from threading import Thread,Lock
    import time
    
    
    money = 100
    mutex = Lock()
    
    
    def task():
        global money
        mutex.acquire()
        tmp = money
        time.sleep(0.1)
        money = tmp - 1
        mutex.release()
    
    
    if __name__ == '__main__':
    
        t_list = []
        for i in range(100):
            t = Thread(target=task)
            t.start()
            t_list.append(t)
        for t in t_list:
            t.join()
        print(money)

    九: GIL全局解释器锁

    9-1 GIL与普通互斥锁的区别

    from threading import Thread,Lock
    import time
    
    
    mutex = Lock()
    money = 100
    
    
    def task():
        global money
        # with mutex:
        #     tmp = money
        #     time.sleep(0.1)
        #     money = tmp -1
        mutex.acquire()
        tmp = money
        time.sleep(0.1)  # 只要你进入IO了 GIL会自动释放
        money = tmp - 1
        mutex.release()
    
    
    if __name__ == '__main__':
        t_list = []
        for i in range(100):
            t = Thread(target=task)
            t.start()
            t_list.append(t)
        for t in t_list:
            t.join()
        print(money)
    
    
    
    """
    100个线程起起来之后  要先去抢GIL
    我进入io GIL自动释放 但是我手上还有一个自己的互斥锁
    其他线程虽然抢到了GIL但是抢不到互斥锁 
    最终GIL还是回到你的手上 你去操作数据

    同一个进程下的多线程无法利用多核优势,是不是就没有用了:

    多线程是否有用要看具体情况
    单核:四个任务(IO密集型计算密集型)
    多核:四个任务(IO密集型计算密集型)
    """
    # 计算密集型 每个任务都需要10s
    单核(不用考虑了)
    多进程:额外的消耗资源
    多线程:介绍开销
    多核
    多进程:总耗时 10+
    多线程:总耗时 40+
    # IO密集型
    多核
    多进程:相对浪费资源
    多线程:更加节省资源

    # 计算密集型
    # from multiprocessing import Process
    # from threading import Thread
    # import os,time
    #
    #
    # def work():
    #     res = 0
    #     for i in range(10000000):
    #         res *= i
    #
    # if __name__ == '__main__':
    #     l = []
    #     print(os.cpu_count())  # 获取当前计算机CPU个数
    #     start_time = time.time()
    #     for i in range(12):
    #         p = Process(target=work)  # 1.4679949283599854
    #         t = Thread(target=work)  # 5.698534250259399
    #         t.start()
    #         # p.start()
    #         # l.append(p)
    #         l.append(t)
    #     for p in l:
    #         p.join()
    #     print(time.time()-start_time)
    
    
    
    # IO密集型
    from multiprocessing import Process
    from threading import Thread
    import os,time
    
    
    def work():
        time.sleep(2)
    
    if __name__ == '__main__':
        l = []
        print(os.cpu_count())  # 获取当前计算机CPU个数
        start_time = time.time()
        for i in range(4000):
            # p = Process(target=work)  # 21.149890184402466
            t = Thread(target=work)  # 3.007986068725586
            t.start()
            # p.start()
            # l.append(p)
            l.append(t)
        for p in l:
            p.join()
        print(time.time()-start_time)

    总结:

    多进程和多线程都有各自的优势
    并且我们后面在写项目的时候通常可以
    多进程下面再开设多线程
    这样的话既可以利用多核也可以介绍资源消耗

    展开全文
  • 编写整洁的并发程序很难——非常难。编写单线程中执行的代码简单得。编写表面上看来不错、深入进去却支离破碎的线程代码也简单。系统一旦遭受压力,这种代码就扛不住了。本章将讨论并发编程的需求及其困难之处...
  • 并发执行多道程序系统中多个程序(逻辑上互相独立)或者一个程序中多个程序段执行过程当中,时间互相重叠,一个程序执行没结束,另一个已经开始。并行执行是指一组程序按照独立,不同步速度执行,时间上...
  • 把多个程序同时装入一个计算机系统主存储器并行执行,称为并发程序设计 1.并发一段时间内完成多个任务执行,或者说是...多道环境下的程序设计叫做并发程序设计 2.并行:同一时刻多个任务同时执行,或者说...
  • 多道批处理系统中,多道程序共享系统资源、并发执行,因此引入了进程的概念。 所以,学习进程之前有必要先对程序的 顺序执行 和 并发执行方式 做简单的了解。 一、前驱图的概念 所谓前驱后继,其实也就是发生...
  • 多道程序设计技术

    千次阅读 多人点赞 2013-09-12 22:06:21
    让多个计算机问题同时装入一个计算机系统的主存储器的并发执行,这种设计技术称为“多道程序设计”,这种计算机系统称为“多道程序设计系统”或简称“多道系统”。 多道程序设计概念 所谓多道程序设计是指允许一个...
  •  Linux 是多道处理系统,当然能够同一段时间内处理多个程序。本文将介绍具体该如何操作。 fork 函数  此函数作用是创建一个子进程,调用后,调用进程和创建新进程就会并发执行( 从调用处开始 )。它调用一...
  • 采用了多道程序设计技术的操作系统具有如下特性 : ① 并发性。它 是指两个或两个以上的事件或活动同一时间间隔内发生。操作系统是一个并发系统,并发性是它的重要特征,操作系统的并发性指计算机系统中同时...
  • 并发就是可以同时执行多程序(本质是不同进程间快速切换执行,并保存程序状态) 总结就是:切换+保存 串行和并发都是程序处理任务方式 为什么要用并发? 可以同时执行多程序,提高了工作效率 提高内存资源...
  • Linux 是多道处理系统,当然能够同一段时间内处理多个程序。 本文将介绍具体该如何操作。 fork 函数 此函数作用是创建一个子进程,调用后,调用进程和创建新进程就会并发执行(从调用处开始)。它调用一次...
  • OS允许计算机系统一个时间段内存在个正在运行的进程,即允许程序的并发执行。OS保证按照“顺序程序设计”方法编制的程序并发执行时不受影响,如同独占计算机。这些按照顺序程序设计思想编制的进程OS中...
  • 为什么说直到出现中断和...多道程序并发执行是指有程序正在CPU上执行,而另一些程序正在I/O设备上进行传输,即通过CPU操作与外设传输时间上重叠减少CPU时间浪费,并提高了系统效率。实现CPU操作与外
  • 进程同步机制-----为进程并发执行保驾护航

    千次阅读 多人点赞 2019-11-07 10:11:52
    本文是对进程同步机制的一个大总结(9000+字吐血总结),涵盖面非常的全,包括了进程同步的一些概念、软件同步...同样我们也知道,OS引入了进程后,可以使系统中的多道程序可以并发的执行,进程的并发执行一方面极...
  • 一、Go并发方式 Go有两种病发编程的风格,分别是:goroutine和通道(channel) 它们支持通信顺序进程(CSP),...顺序程序可能调用一个函数,然后调用另一个,但是有两个或个goroutine的并发程序中,两个函数可以
  • 线程和并发问题是Java技术面试中面试官比较喜欢问问题之一。这里,从面试角度列出了大部分重要问题,但是你仍然应该牢固掌握Java线程基础知识来对应日后碰到问题。(校对注:非常赞同这个观点) ...
  • 从头开始自学java 2017-05-12 00:52 Java是一门语言级别支持线程的语言。 线程的概念 线程是程序执行的最小单位,也是操作系统调度和...进程是程序的实体,也是线程的容器,一个进程可以包含个线程,进程是资
  • 前驱图和程序执行

    2020-03-10 23:36:05
    在多道程序环境中,允许多个程序并发执行;程序本身是具体代码,不能反映程序的执行过程从而引入进程。 进程是抽象的。作为资源分配和独立运行的基本单位是进程。操作系统所有的特征都是基于进程而体现的。 程序...
  • 掌握程序中创建新进程方法, 观察并理解多道程序并发执行的现象。 三、实验原理 fork():建立子进程。子进程得到父进程地址空间一个复制。 返回值:成功时,该函数被调用一次,但返回两次,fork()对子进程...
  • 服务端程序每一时刻都经受着大量并发流量考验,而如今,CPU 指令运行频率提升已经面临瓶颈,只能通过核心数增长来大幅提升其指令的执行能力。 因此,现代程序设计中,并发编程支持就显得越来越重要。...
  • goroutine指每一个并发执行的活动。main函数主goroutine中执行。goroutine通过go关键字创建。 go f() // 新建一个goroutine调用f(),go语句本身立即返回 main函数返回时,所有goroutine直接终结,程序退出。除此...
  • Go语言并发

    2019-12-13 16:12:50
    2、竞争条件:当两个或者个操作必须按正确顺兴执行,而程序并未保证这个顺序就会发生竞争条件。 大多数情况下,这将所谓数据中出现,其中一个并发操作尝试读取一个变量,而某个不确定时间,另一个并发...
  • 基于景老师博客https://www.cnblogs.com/Eva-J/articles/8253549.html#_label2和 egon老师博客 http://www.cnblogs.com/linhaifeng/p/6295875.html 整理 ...多道程序系统 原理,缺点 #允许多个程...
  • 在多道程序环境下,并发性是指一段时间宏观上有多个程序同时运行,但单处理机系统中,每一时刻却仅能只有一道程序在执行,故微观上这些程序只能是分时交替执行。   所以可能不是并发要解决什么问题,而是...
  • 在多道程序环境下,并发性是指一段时间宏观上有多个程序同时运行,但单处理机系统中,每一时刻却仅能只有一道程序在执行,故微观上这些程序只能是分时交替执行。   打个比方:你一家公司工作,boss让你既...
  • 1.5.1 并行性与并发区别和联系

    千次阅读 2016-06-19 22:18:31
    在多道程序环境下,并发性是指一段时间内,宏观上有多个程序同时运行,但单处理器系统中每个时刻却仅有一道程序执行,故微观上这些程序只能分时地交替执行。倘若计算机系统中有多个处理器,则这些可以并发...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,275
精华内容 510
关键字:

多道程序的并发执行在