zoukankan      html  css  js  c++  java
  • 并发

    一、操作系统发展史

      1.穿孔卡片

      2.磁带

      3.批处理

      本质:都是想提高CPU的利用率

    二、多道技术

      1.空间上的复用

        多个程序公用一台硬件设备

      2.时间上的复用(洗衣,做饭,烧水)

        cpu在多个程序之间来回切换着执行程序

        cpu什么时候会切换:

          (1)程序占用cpu时间过长,操作系统会剥夺该程序的cpu执行权限(降低了程序的执行效率)

          (2)程序遇到IO操作,操作系统会剥夺该程序的cpu执行权限(提高了利用率,并且也不影响程序的执行效率)

        并发:看起来像同时运行的就可以

        并行:真正意义上的同时执行,单核的计算机能不能实现并行,但是可以实现并发

    三、进程理论

      1.程序:一堆代码

       进程:正在运行的程序

      2.同步异步:表示的是任务的提交方式

        同步:任务提交之后,原地等待的任务的执行并拿到返回结果才走,期间不做任何事(程序层面的表现就是卡住了)

        异步:任务提交之后,不再原地等待,而是继续执行下一行代码(结果是要的,但是是用其他方式获取)

      3.阻塞非阻塞:表示的程序的运行状态

        阻塞:阻塞态

        非阻塞:就绪态,运行态

        强调:同步异步,阻塞非阻塞是两对概念,不能混为一谈

    四、创建进程的两种方式

      1.创建进程就是在内存中重新开辟一块内存空间,

        将允许产生的代码丢进去

        一个进程对应在内存就是一块独立的内存空间

      2.进程与进程之间数据是隔离的,无法直接交互,

        但是可以通过某些技术实现间接交互

      3.windows创建进程会将代码以模块的方式,从上往下执行一遍

       linux会直接将代码完完整整的拷贝一份

       windows创建进程一定要在if __name__ == '__main__':代码块内创建,否则报错

      4.方法一:

    from multiprocessing import Process
    import time
    
    
    def test(name):
        print('%s is running'%name)
        time.sleep(3)
        print('%s is over'%name)
    
    if __name__ == '__main__':
        p = Process(target=test,args=('egon',))  # 创建一个进程对象
        p.start()  # 告诉操作系统帮你创建一个进程
        print('')

      方式二:

    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(3)
            print('%s is over' % self.name)
    
    if __name__ == '__main__':
        p = MyProcess('egon')
        p.start()
        print('')

    五、进程方法join

      start()作用仅仅是告诉操作系统帮你创建一个进程,至于这个进程什么时候创建由操作系统随机决定

      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()
        p = Process(target=test,args=('egon',1))
        p1 = Process(target=test,args=('kevin',2))
        p2 = Process(target=test,args=('jason',3))
        start_time = time.time()
        p.start()  # 仅仅是告诉操作系统帮你创建一个进程 至于这个进程什么时候创  操作系统随机决定
        p1.start()
        p2.start()
        p2.join()
        p.join()
        p1.join()
    
        # 主进程代码等待子进程运行结束 才继续运行
        # p.join()  # 主进程代码等待子进程运行结束
        print('')
        print(time.time() - start_time)

    六、进程对象及其他方法

      查看进程id号

        current_process().pid  >>>  current_process()返回的是Process()

        os.getpid()  os.getppid()

      terminate()作用是杀死当前进程,其实是告诉操作系统帮你杀死一个进程

      is_alive()作用是判断进程是否存活

    from multiprocessing import Process,current_process
    import os
    import time
    
    
    def test(name):
        # print('%s is running'%name,current_process().pid)
        print('%s is running'%name,'子进程%s'%os.getpid(),'父进程%s'%os.getppid())
        time.sleep(3)
        print('%s is over'%name)
    
    
    if __name__ == '__main__':
        p = Process(target=test,args=('egon',))
        p.start()
        p.terminate()  # 杀死当前进程  其实是告诉操作系统帮你杀死一个进程
        time.sleep(0.1)
        print(p.is_alive())  # 判断进程是否存活
        # print('主',current_process().pid)
        print('',os.getpid(),'主主进程:%s'%os.getppid())

    七、进程间数据互相隔离

      如何验证  开一个子进程修改主进程里面的数据,根本无法修改

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

    八、守护进程

      主进程一旦运行完毕,子进程立即结束运行(一起死!)

      p.daemon = True作用是将进程设置为守护进程,这一句话必须放在start语句之前,否则报错

    from multiprocessing import Process
    import time
    
    
    def test(name):
        print('%s总管正常活着'%name)
        time.sleep(3)
        print('%s总管正常死亡'%name)
    
    
    if __name__ == '__main__':
        p = Process(target=test,args=('egon',))
        p.daemon = True  # 将该进程设置为守护进程   这一句话必须放在start语句之前 否则报错
        p.start()
        time.sleep(0.1)
        print('皇帝jason寿正终寝')

    九、互斥锁

      当多个进程操作同一份数据的时候,会造成数据的错乱

        这个时候必须加锁处理,将并发变成串行

        虽然降低了效率,但是提高了数据的安全

      注意:

        1.锁不要轻易使用,容易造成死锁现象

        2.只在处理数据的部分加锁,不要在全局加锁

      锁必须在主进程中产生,交给子进程去使用

      mutex.ecquire()  # 抢锁  一把锁不能同时被多个人使用,没有抢到的人就一直等待锁的释放

      buy(1)

      mutex.release()  # 释放锁

      抢票模拟

    from multiprocessing import Process,Lock
    import time
    import json
    
    # 查票
    def search(i):
        with open('data','r',encoding='utf-8') as f:
            data = f.read()
        t_d = json.loads(data)
        print('用户%s查询余票为:%s'%(i,t_d.get('ticket')))
    
    # 买票
    def buy(i):
        with open('data','r',encoding='utf-8') as f:
            data = f.read()
        t_d = json.loads(data)
        time.sleep(1)
        if t_d.get('ticket') > 0:
            # 票数减一
            t_d['ticket'] -= 1
            # 更新票数
            with open('data','w',encoding='utf-8') as f:
                json.dump(t_d,f)
            print('用户%s抢票成功'%i)
        else:
            print('没票了')
    
    
    def run(i,mutex):
        search(i)
        mutex.acquire()  # 抢锁  只要有人抢到了锁 其他人必须等待该人释放锁
        buy(i)
        mutex.release()  # 释放锁
    
    
    if __name__ == '__main__':
        mutex = Lock()  # 生成了一把锁
        for i in range(10):
            p = Process(target=run,args=(i,mutex))
            p.start()

    十、僵尸进程与孤儿进程

      子进程结束之后不会立即释放pid等资源信息

      主进程释放子进程资源的两种情况:

        主进程正常死亡

        join方法

      1.所有的进程都会步入僵尸进程

        父进程回收子进程资源的两种方式

          (1)join方法

          (2)父进程正常死亡

      2.孤儿进程

        子进程没死,父进程意外死亡

        针对linux会有儿童福利院(init),如果父进程意外死亡他所创建的子进程都会被福利收养

  • 相关阅读:
    WebApi Ajax 跨域请求解决方法(CORS实现)
    JQuery Ajax POST/GET 请求至 ASP.NET WebAPI
    Hybird APP对接后台:Net WebApi
    Chrome
    centos8平台:用fontconfig安装及管理字体(fc-list/fc-match/fc-cache)
    centos8平台:redis6配置启用io多线程(redis6.0.1)
    centos8平台安装redis6.0.1
    centos8平台:举例讲解redis6的ACL功能(redis6.0.1)
    ImageMagick实现图片加水印(ImageMagick6.9.10)
    centos8上安装ImageMagick6.9.10并压缩图片生成webp缩略图
  • 原文地址:https://www.cnblogs.com/yljbky/p/11328493.html
Copyright © 2011-2022 走看看