• day30 进程 同步 异步 阻塞 非阻塞 并发 并行 创建进程 守护进程 僵尸进程与孤儿进程 互斥锁


    操作系统发展史

    1.第一带计算机   真空管和穿孔卡片  没有进程 没有操作系统   
    
    ​    2.第二代计算机  7094 1401    晶体管  批处理系统 
    
    ​        输入输出  以及计算设备 不能互联  需要人参与    一批一批的处理   开发效率慢  并且串行执行
    
    ​    3.第三代计算机    集成电路 与多道技术 
    
    ​        多终端联机  spooling      同一台机器既能进行科学计算  又能做字符处理       通用计算机
    
    ​        多道技术   解决串行导致的效率低下问题
    
    ​        多用户终端    可以同时为多个用户提供服务  每个用户以为自己独享一台计算机   
    
    ​    4.第四代   个人电脑
    
    ​        大规模使用了集成电路,大多都提供了GUI界面  

    多道技术

    产生背景 ,所有程序串行 导致资源浪费

    目的是让多个程序可以并发执行 , 同时处理多个任务

    空间复用
    
    指的是 同一时间 内存中加载多个不同程序数据,
    
    每个进程间内存区域相互隔离,物理层面的隔离  
    
     时间复用       切换 + 保存
    
     切换条件:
    
    1.一个进程执行过程中遇到了IO操作  切换到其他进程
    
    2.运行时间过长,会被操作系统强行剥夺执行权力   
    
    单纯的切换不够,必须在切换前保存当前的状态,以便于恢复执行

    进程

    一个正在被运行的程序就称之为进程,是程序具体执行过程,一种抽象概念

    进程来自于操作系统

    进程和程序的区别

    程序就是一堆计算机可以识别文件,程序在没有被运行就是躺在硬盘上的一堆二进制

    运行程序时,要从硬盘读取数据到内存中,CPU从内存读取指令并执行 ,

    一旦运行就产生了进程

    一个程序可以多次执行 产生多个进程,但是进程之间相互独立

    当我们右键运行了一个py文件时 ,其实启动的是python解释器,你的py文件其实是当作参数传给了解释器

    同步 异步 阻塞 非阻塞 并发 并行

    同步 异步 指的是任务的提交方式
    1.同步:任务提交之后 原地等待的任务的执行并拿到返回结果才走 期间不做任何事(程序层面的表现就是卡住了)
    
    2.异步:任务提交之后 不再原地等待 而是继续执行下一行代码(结果是要的 但是是用过其他方式获取)
    阻塞 非阻塞 指的是程序的运行状态
    阻塞 : 程序遇到io操作是就进入了阻塞状态  ,程序无法继续执行其他代码
    
    ​	本地IO input      print     sleep    read  write       
    
    ​	网络IO recv  send
    
    非阻塞: 程序正常运行中 没有任何IO操作   就处于非阻塞状态  ,或者通过某种方式使程序即时遇到了也不会停在原地,还可以执行其他操作,以提高CPU的占用率
    
    并发 并行 说的是 任务的处理方式
    并发: 多个任务看起来同时在处理 ,本质上是切换执行     速度非常快    
    
    并行: 多个任务真正的同时执行    必须具备多核CPU  才可能并行  
    

    进程的三种状态

      

     

    就绪态,运行态,和阻塞态

    多道技术会在进程执行时间过长或遇到IO时自动切换其他进程,意味着IO操作与进程被剥夺CPU执行权都会造成进程无法继续执行

    创建进程

    创建进程就是在内存中重新开辟一块内存空间,将允许产生的代码丢进去,一个进程对应在内存就是一块独立的内存空间
    进程与进程之间数据是隔离的 无法直接交互,但是可以通过某些技术实现间接交互
    实例化Process,将要执行任务用target传入
    from multiprocessing import Process
    import time
    
    
    def test(name):
        print('%s is running'%name)
        time.sleep(2)
        print('%s is over'%name)
    
    # windows创建进程会将代码以模块的方式 从上往下执行一遍
    # linux会直接将代码完完整整的拷贝一份
    # windows创建进程一定要在if __name__ == '__main__':代码块内创建  否则报错
    
    if __name__ == '__main__':
        # 创建一个进程对象
        p = Process(target=test,args=('lolo',))
        # 告诉操作系统帮你创建进程
        p.start()
        print('')
    1
    继承Process,并覆盖run方法, 将任务放入run方法中  
    from multiprocessing import Process
    import time
    class MyProcess(Process):
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('%s is running'%self.name)
            time.sleep(2)
            print('%s is over'%self.name)
    
    if __name__ == '__main__':
        p = MyProcess('coco')
        p.start()
        print('')
    2
    1.在windows下 开启子进程必须放到__main__下面,因为windows在开启子进程时会重新加载所有的代码造成递归创建进程
    
    2.第二种方式中,必须将要执行的代码放到run方法中,子进程只会执行run方法其他的一概不管
    
    进程间内存相互隔离

    join函数

    Process的对象具备一个join函数

    用于提高子进程优先级 ,使得父进程等待子进程结束

    from multiprocessing import Process
    import time
    
    def test(name,i):
        print('%s is running'%name)
        time.sleep(i)
        print('%s is over'%name)
    
    if __name__ == '__main__':
        p_list = []
        for i in range(3):
            p = Process(target=test,args=('进程%s'%i,i))
            p.start()
            p_list.append(p)
        for p in p_list:
            p.join()
        p1 = Process(target=test,args=('dodo',2))
        p2 = Process(target=test,args=('lolo',1))
        p1.start()
        p2.start()
        p1.join()
    View Code

    进程间相互隔离

    from multiprocessing import Process
    
    
    money = 100
    
    def test():
        global money
        money = 888
    
    if __name__ == '__main__':
        p = Process(target=test)
        p.start()
        p.join()
        print(money)
    验证

    进程对象及其它方法

    from multiprocessing import Process,current_process,active_children
    import os
    import time
    
    
    def test(name):
        print('%s is running'%name,current_process().pid)
        print('%s run'%name,os.getpid(),os.getppid())
        time.sleep(1)
        print('%s is over'%name)
    
    if __name__ == '__main__':
        p = Process(target=test,args=('lolo',))
        p.start()
        p.terminate()
        # 杀死当前进程  其实是告诉操作系统帮你杀死一个进程
        print(p.is_alive())
        # 判断进程是否存活
        print('',os.getpid(), os.getppid())
    View Code
    # p.join() # 等待子进程结束
    # p.terminate()  # 终止进程
    # print(p.name)  # 进程的名称
    # print(p.is_alive()) #是否存活
    # p.terminate() # 与start一样 都是给操作系统发送指令 所以会有延迟
    # print(p.is_alive())
    # print(p.pid)
    # print(p.exitcode) # 获取退出码
    

      

    守护进程

    进程:一个正在运行的程序。
    
    主进程创建守护进程:
    
    1.守护进程会在主进程代码执行结束后就终止,
    
    2.守护进程内无法再开启子进程,否则抛出异常。
    
    注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止。
    from multiprocessing import Process
    import time
    
    
    def teat(name):
        print('%s 在'%name)
        time.sleep(1)
        print('%s 不在'%name)
    
    if __name__ == '__main__':
        p = Process(target=teat,args=('coco',))
        p.daemon = True
        p.start()
        # p.daemon = True
        time.sleep(0.1)
        print('老板不在')
    View Code

    僵尸进程与孤儿进程

    孤儿进程
    孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程
    
    孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。
    
    僵尸进程
    僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!
    
    僵尸进程的危害:
     
    
    由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。
    在Linux中,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,
    在python中,已经封装好了wait操作不需要我们自己清理。
    但是系统所能使用的进程号是有限的,如果大量的产生[僵死进程],将因为没有可用的进程号而导致系统不能产生新的进程. 此为僵尸进程的危害,应当避免。
    

      

    互斥锁

    互相排斥的锁(如果这个资源已经被锁了,其他进程就无法使用了)
    需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行。
    使用场景:  
      并发将带来资源的竞争问题,
    当多个进程同时要操作同一个资源时,将会导致数据错乱的问题。
    

     

    解决方案1:
    
    ​ 加join,
    
    例子:
    from multiprocessing import Process
    import time
    
    
    def task1():
        print('你好,阿森。。。')
        time.sleep(3)
        print('吃饭')
        time.sleep(3)
        print('下雨')
    
    
    def task2():
        print('你好,阿三。。。')
        time.sleep(3)
        print('吃面')
        time.sleep(3)
        print('下雪')
    
    
    def task3():
        print('你好,阿四。。。')
        time.sleep(3)
        print('吃米')
        time.sleep(3)
        print('下冰雹')
    
    
    if __name__ == '__main__':
        p1 = Process(target=task1)
        p2 = Process(target=task2)
        p3 = Process(target=task3)
    
        p1.start()
        p1.join()
        p2.start()
        p2.join()
        p3.start()
        p3.join()
    ​ 弊端: 1.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了。
    
    ​        2.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的。
    
    解决方案2:
    
    ​ 就是给公共资源加 锁----互斥锁。
    
    例子:
    
    from multiprocessing import Process,Lock
    import time,random
    def task1(lock):
        # 上锁
        lock.acquire()      #就等同于一个if判断
        print('你好,阿森。。。')
        time.sleep(random.randint(0,3))
        print('吃饭')
        time.sleep(random.randint(0, 3))
        print('下雨')
        #解锁
        lock.release()
    
    
    def task2(lock):
        lock.acquire()
        print('你好,阿三。。。')
        time.sleep(random.randint(0, 3))
        print('吃面')
        time.sleep(random.randint(0, 3))
        print('下雪')
        lock.release()
    
    
    def task3(lock):
        lock.acquire()
        print('你好,阿四。。。')
        time.sleep(random.randint(0, 3))
        print('吃米')
        time.sleep(random.randint(0, 3))
        print('下冰雹')
        lock.release()
    
    
    if __name__ == '__main__':
        lock=Lock()
        p1=Process(target=task1,args=(lock,))
        p2=Process(target=task2,args=(lock,))
        p3=Process(target=task3,args=(lock,))
    
        p1.start()
        p2.start()
        p3.start()
    View Code
    # 注意1:  不要对同一把执行多出acquire 会锁死导致程序无法执行  一次acquire必须对应一次release
    
    from multiprocessing import Lock
    l=Lock()
    l.acquire()
    print('抢到了')
    l.release()
    
    l.acquire()
    print('接着抢')
    
    # 注意2:想要保住数据安全,必须保住所有进程使用同一把锁
    锁和join的区别:
    
    1.  join是固定了执行顺序,会造成父进程等待子进程完成后完成
    
    ​	   锁是公平竞争谁先抢到谁先执行,父进程可以做其他事情、
    
    2.  join是把进程的任务全部串行
    
    ​	  锁可以锁任意代码 ,一行也可以 可以自己调整粒度
    
    粒度:
    
    粒度越大意味着锁住的代码越多 效率越低
    粒度越小意味着锁住的代码越少 效率越高
    
    MYSQL 中不同隔离级别 其实就是不同的粒度  

     小练习 -- 抢票

    """
    过程:
    1.查看余票,
    2.有就买,无失败
     os.getpid()获取当前进程id
    #文件db的内容为:{"count":1}
    #注意一定要用双引号,不然json无法识别
    
    """
    from multiprocessing import Process, Lock
    import json, random, time, os
    
    
    def check_ticket():
        with open('ticket.json', 'rt', encoding='utf-8')as a:
            data = json.load(a)
            time.sleep(random.randint(0, 3))
            print('%s正在查票,票还有%s' % (os.getpid(), data["count"]))
    
    
    def buy_ticket():
        with open('ticket.json', 'rt', encoding='utf-8')as a:
            data = json.load(a)
            if data["count"] > 0:
                data["count"] -= 1
                # 模拟延迟
                time.sleep(random.randint(0, 3))
                with open('ticket.json', 'wt', encoding='utf-8')as a:
                    json.dump(data, a)
                    print('%s恭喜你抢票成功' % os.getpid())
    
            else:
                print('%s抢票失败,开个加速包试一试' % os.getpid())
    
    
    def task(lock):
        check_ticket()
        lock.acquire()
        buy_ticket()
        lock.release()
    
    
    if __name__ == '__main__':
    
        lock = Lock()
        # 三个人抢票
        for i in range(10):
            p = Process(target=task, args=(lock,))
            p.start()
    抢票
  • 相关阅读:
    iOS 定位坐标不准确的相关整理及解决方案汇总
    ASIHTTPRequest 类库在iOS 7.0中,会有一些报错警告,需要稍作修改
    2013年9月29日 iOS 周报
    适配iOS7之—UITableView和UISearchBar
    IOS开发~开机启动&无限后台运行&监听进程
    IOS开发~灵活使用 dismissViewControllerAnimated / dismissModalViewControllerAnimated
    IOS7开发~API变化
    IOS7开发~NSAttributedString
    IOS7开发~新UI学起(三)
    关于14道魔鬼js考题的整理
  • 原文地址:https://www.cnblogs.com/komorebi/p/11348565.html
Copyright © 2020-2023  润新知