zoukankan      html  css  js  c++  java
  • day38---并发编程理论基础

    操作系统的发展历史

    • 真空管和穿孔卡片

      """
      优点:程序员在申请的时间段内独享整个资源,可以即时地调试自己的程序
      缺点:浪费计算机资源,一个时间段内只有一个人用。
      """
      

      特点: 没有操作系统的概念 所有的程序设计都是直接操控硬件

    • 晶体管和批处理系统

      • 联机批处理系统

      • 脱机批处理系统

        其功能是:

        #
        (1) 从输入机上读取用户作业并放到输入磁带上
        (2) 从输出磁带上读取执行结果并传给输出机
        #
        

        这样,主机不是直接与慢速的输入/输出设备打交道,而是与速度相对较快的磁带机发生关系,有效缓解了主机与设备的矛盾。主机与卫星机可并行工作,二者分工明确,可以充分发挥主机的高速计算能力。

    多道技术程序系统

    多道程序设计技术

    (1)定义:

    #所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。
    

    ​ 在A程序计算时,I/O空闲, A程序I/O操作时,CPU空闲(B程序也是同样);必须A工作完成后,B才能进入内存中开始工作,两者是串行的,全部完成共需时间=T1+T2。

    ​ 将A、B两道程序同时存放在内存中,它们在系统的控制下,可相互穿插、交替地在CPU上运行:当A程序因请求I/O操作而放弃CPU时,B程序就可占用CPU运行,这样 CPU不再空闲,而正进行A I/O操作的I/O设备也不空闲,显然,CPU和I/O设备都处于“忙”状态,大大提高了资源的利用率,从而也提高了系统的效率,A、B全部完成所需时间<<T1+T2。

    ​ 多道程序设计技术不仅使CPU得到充分利用,同时改善I/O设备和内存的利用率,从而提高了整个系统的资源利用率和系统吞吐量(单位时间内处理作业(程序)的个数),最终提高了整个系统的效率。

    时间和空间上的复用

    1. 空间上的复用:多个应用程序共用一个计算机硬件

    2. 时间上的复用:

      #
      例子:洗衣服30s,做饭50s,烧水30s
      
      单道需要110s,多道只需要任务做长的那一个 		切换节省时间
      
      例子:边吃饭边玩游戏							   保存状态
      #
      

    切换加保存状态

    """
    切换(CPU)分为两种情况
    	1.当一个程序遇到IO操作的时候,操作系统会剥夺该程序的CPU执行权限
    		作用:提高了CPU的利用率 并且也不影响程序的执行效率
    	
    	2.当一个程序长时间占用CPU的时候,操作吸引也会剥夺该程序的CPU执行权限
    		弊端:降低了程序的执行效率(原本时间+切换时间)
    """
    

    进程的发展史及演变

    • 什么是进程?

      #进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
      

      理论角度来看:

      进程,是对正在运行程序过程的抽象

      实现角度来看:

      进程,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。

    • 进程的调度算法

      1. 先来先服务算法

        算法比较有利于长作业(进程),而不利于短作业(进程)。由此可知,本算法适合于CPU繁忙型作业,而不利于I/O繁忙型的作业(进程)。
        
      2. 短作业优先调度算法

        短作业(进程)优先调度算法(SJ/PF)是指对短作业或短进程优先调度的算法,该算法既可用于作业调度,也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理;作业的长短只是被估算出来的。
        
      3. 时间片轮转法+多级反馈序列

    • 进程的并行与并发

      • 并行:并行是指两者同时执行
      • 并发:并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率。

    同步异步阻塞非阻塞

    进程的三种状态图

    在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。

    """
    (1)就绪(Ready)状态
    
    当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
    
    (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
    
    (3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
    """
    
    • 同步
    #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回。按照这个定义,其实绝大多数函数都是同步调用。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
    

    例如:

    def test():
        name = input('enter your name >>:').strip()
        print(name)
    

    程序要等待用户input输入后才能继续运行。

    #1. multiprocessing.Pool下的apply #发起同步调用后,就在原地等着任务结束,根本不考虑任务是在计算还是在io阻塞,总之就是一股脑地等任务结束
    #2. concurrent.futures.ProcessPoolExecutor().submit(func,).result()
    #3. concurrent.futures.ThreadPoolExecutor().submit(func,).result()
    
    • 异步
    #所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
    

    例如:

    #1. multiprocessing.Pool().apply_async() #发起异步调用后,并不会等待任务结束才返回,相反,会立即获取一个临时结果(并不是最终的结果,可能是封装好的一个对象)。
    #2. concurrent.futures.ProcessPoolExecutor(3).submit(func,)
    #3. concurrent.futures.ThreadPoolExecutor(3).submit(func,)
    
    • 阻塞
    #阻塞调用是指调用结果返回之前,当前线程会被挂起(如遇到io操作)。函数只有在得到结果之后才会将阻塞的线程激活。有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。
    

    例如:

    #1. 同步调用:apply一个累计1亿次的任务,该调用会一直等待,直到任务返回结果为止,但并未阻塞住(即便是被抢走cpu的执行权限,那也是处于就绪态);
    #2. 阻塞调用:当socket工作在阻塞模式的时候,如果没有数据的情况下调用recv函数,则当前线程就会被挂起,直到有数据为止。
    
    • 非阻塞
    #非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前也会立刻返回,同时该函数不会阻塞当前线程。
    

    上述概念的组合:最高效的一种组合就是异步非阻塞

    进程创建的两种方式

    第一种

    from multiprocessing import Process
    import time
    
    
    def beast(name):
        print('天王盖地虎'.center(30, '='))
        time.sleep(3)
        print(f'{name}一米五'.center(30, '^'))
    
    
    if __name__ == '__main__':
        """
        1.创建一个对象
        """
        p = Process(target=beast, args=('egon',))
        p.start()  # 告诉系统帮你创建一个进程,异步
        print('我是主程序'.center(30,'*'))
    

    第二种

    from multiprocessing import Process
    import time
    
    
    class MyProcess(Process):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('天王盖地虎'.center(30, '='))
            time.sleep(5)
            print(f'{self.name}一秒五'.center(30, '^'))
    
    if __name__ == '__main__':
        p = MyProcess('egon')
        p.start()
        print('我是主程序'.center(30,'*'))
    

    总结

    """
    创建进程就是在内存中申请一块内存空间将需要运行的代码丢进去
    一个进程对应在内存中就是一块独立的内存空间
    多个进程对应在内存中就是多块独立的内存空间
    进程与进程之间数据默认情况下是无法直接交互,如果想交互可以借助于第三方工具、模块
    """
    

    注意

    #在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候  ,就不会递归运行了。
    

    join 方法的使用

    join是让主进程等待子进程代码运行结束之后,再继续运行。不影响其他子进程的执行

    from multiprocessing import Process
    import time
    
    
    def task(name, n):
        print('%s is running'%name)
        time.sleep(n)
        print('%s is over'%name)
    
    
    if __name__ == '__main__':
        # p1 = Process(target=task, args=('jason', 1))
        # p2 = Process(target=task, args=('egon', 2))
        # p3 = Process(target=task, args=('tank', 3))
        # start_time = time.time()
        # p1.start()
        # p2.start()
        # p3.start()  # 仅仅是告诉操作系统要创建进程
        # # time.sleep(50000000000000000000)
        # # p.join()  # 主进程等待子进程p运行结束之后再继续往后执行
        # p1.join()
        # p2.join()
        # p3.join()
        start_time = time.time()
        p_list = []
        for i in range(1, 4):
            p = Process(target=task, args=('子进程%s'%i, i))
            p.start()
            p_list.append(p)
        for p in p_list:
            p.join()
        print('主', time.time() - start_time)
    

    进程之间数据的相互隔离

    from multiprocessing import Process
    
    
    money = 100
    
    
    def task():
        global money  # 局部修改全局
        money = 666
        print('子',money)
    
    
    if __name__ == '__main__':
        p = Process(target=task)
        p.start()
        p.join()
        print(money)
    

    1587544869585

  • 相关阅读:
    [转]tf.summary() 用法
    PASCAL VOC工具包解读
    [ERROR] 安装完Detectron后出现 cython_nms.so: undefined symbol: PyFPE_jbuf
    用Tensorflow做蝴蝶检测
    双系统,重装ubuntu后无法进入windows
    [Error]NodeDef mentions attr 'identical_element_shapes' not in Op<name=TensorArrayV3;
    [转]调试 smallcorgi/Faster-RCNN_TF 的demo过程遇到的问题
    js交互轮播图
    js取俩个数之间的随机数
    原生js实现触摸滚动轮播图
  • 原文地址:https://www.cnblogs.com/surpass123/p/12753132.html
Copyright © 2011-2022 走看看