zoukankan      html  css  js  c++  java
  • Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁

    一 计算机发展史

    操作系统本质上是一个软件

    主要功能:

      1、控制硬件,隐藏丑陋复杂的硬件细节

      2、将无序的硬件竞争变得有序

    第一代计算机(1940~1955):真空管和穿孔卡片

    第二代计算机(1955~1965):晶体管和批处理系统

    第三代计算机(1965~1980):集成电路芯片和多道程序设计

             第三代计算机的操作系统仍然是批处理

    第四代计算机(1980~至今):个人计算机

    二 多道技术(第三代计算机出现)

    1.产生背景:针对单核,实现并发
        ps:
        现在的主机一般是多核,那么每个核都会利用多道技术
        有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
        cpu中的任意一个,具体由操作系统调度算法决定。
        
        2.空间上的复用:如内存中同时有多道程序
        3.时间上的复用:复用一个cpu的时间片
           强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
                才能保证下次切换回来时,能基于上次切走的位置继续运行
    View Code

    空间复用:多个程序共用一套计算机硬件,每个程序间的内存都是相互隔离的(物理隔离)

    时间复用(切换+保存):当一个程序执行IO操作时,切换到另一个程序来执行,光切换还不行 必须在切换前保存当前的状态 以便与恢复执行。

    注意:并不是多道就一定提高了效率
    如果多个任务都是纯计算 那么切换反而降低了效率
    遇到IO操作才应该切换 这才能提高效率

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

    #同步和异步指的是任务的提交方式

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

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

    #阻塞和非阻塞指的程序运行的状态

    1.阻塞:当程序执行过程中遇到了IO操作,在执行IO操作时,程序无法继续执行其他代码,称为阻塞!

    2.非阻塞:程序在正常运行没有遇到IO操作,或者通过某种方式使程序即时遇到了也不会停在原地,还可以执行其他操作,以提高CPU的占用率

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

    并发:指的是多个进程快速切换执行,间隔时间很短看起来像是同时执行的。

    并行:真正意义上的多个进程同时执行的(多核cpu才能完成)

    进程的三种状态

    四 进程

    1.什么是进程:正在运行的程序,程序是程序员编程的一堆代码(字符串),当这对代码被系统加载的内存中执行时,就有了进程(也是操作系统在调度和进行资源分配的基本单位) 

     当一个进程a开启了另一个进程b时,a称为b的父进程,b称为a的子进程

    2.实现进程的两种方式

    1.实例化Process类
    from multiprocessing import Process
    import time
    
    def task(name):
        print('%s is running' %name)
        time.sleep(3)
        print('%s is done' %name)
    if __name__ == '__main__':
        # 在windows系统之上,开启子进程的操作一定要放到这下面
        # Process(target=task,kwargs={'name':'egon'})
        p=Process(target=task,args=('jack',)) # 实例化产生进程对象
        p.start() # 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,作为子进程的初始状态
        print('======主')
    
    2.继承Process类 并覆盖init 和 run方法
    from multiprocessing import Process
    import time
    
    class MyProcess(Process):
        def __init__(self,name):
            super(MyProcess,self).__init__()
            self.name=name
    
        def run(self):
            print('%s is running' %self.name)
            time.sleep(3)
            print('%s is done' %self.name)
    if __name__ == '__main__':
        p=MyProcess('jack')
        p.start()
    
    需要注意的是 
    
    1.在windows下 开启子进程必须放到`__main__`下面,因为windows在开启子进程时会重新加载所有的代码造成递归创建进程
    
    2.第二种方式中,必须将要执行的代码放到run方法中,子进程只会执行run方法其他的一概不管
        print('')
    View Code

    3.进程中的join()函数  阻塞

    Process的对象具备一个join函数

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

    from multiprocessing import Process
    
    def task():
        print("子进程 Game Over")
    
    if __name__ == '__main__':
        p = Process(target=task)
        p.start()
        p.join()    # 等待子进程执行完毕,将子进程的优先级提高
        print("主进程 Game Over")    # 子进程 Game Over
                                     # 主进程 Game Over
    View Code

    4.进程中的内存都是相互隔离的

    from multiprocessing import Process
    x = 10
    def task():
        global x
        x = 100
        print("子进程",x)   # 子进程 100
    
    if __name__ == '__main__':
        p = Process(target=task)
        p.start()
        print("父进程",x)    # 父进程 10
    
    
    创建进程就是在内存中重新开辟一块内存空间
    将允许产生的代码丢进去
    一个进程对应在内存就是一块独立的内存空间
    
    进程与进程之间数据是隔离的 无法直接交互
    但是可以通过某些技术实现间接交互
    View Code

    5.进程对象及其他方法

    from multiprocessing import Process
    def task(n):
        print('%s is runing' %n)
        time.sleep(n)
    
    if __name__ == '__main__':
        start_time=time.time()
        p1=Process(target=task,args=(1,),name='任务1')
        p1.start() # 启动进程
        print(p1.pid) # 获取进程pid
        print(p1.name) # 获取进程名字
        p1.terminate() # 终止进程
        p1.join() # 提高优先级
        print(p1.is_alive()) # 获取进程的存活状态
        print('')
    View Code

    6.pid和ppid

    #1.什么是pid: 一个操作系统中通常都会运行多个应用程序,也就是多个进程,那么如何来区分进程呢?系统会给每一个进程分配一个进程编号即PID,如同人需要一个身份证号来区分。

    #2.

    # 在python中可以使用os模块来获取ppid
    import os
    print("self",os.getpid()) # 当前进程自己的pid
    print("parent",os.getppid()) # 当前进程的父进程的pid
    View Code

    四 进程中的孤儿进程和僵尸进程

    1.什么是孤儿进程:

    孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程

    例如:qq聊天中别人发给你一个链接,点击后打开了浏览器,那qq就是浏览器的父进程,然后退出qq,此时浏览器就成了孤儿进程

    孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。

    2.什么是僵尸进程:僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源!

    五 进程中的守护进程

    1.什么是守护进程:一个进程可以守护另一个进程。开启守护进程是为了并发执行某个任务,但这个任务如果伴随着主进程的结束而没有存在的意义,就可以将子进程设为守护进程。比如:qq接收到一个视频文件,于是开启了一个子进程来下载,如果中途退出了,下载任务就没必要继续下去。如果b是a的守护进程,a是被守护的进程,如果a挂了,则b也随之结束。

    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寿正终寝')
    View Code

    六 进程中的互斥锁

    1.什么是互斥锁:

    互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)

    需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行

    为什么需要互斥锁:

    并发将带来资源的竞争问题 当多个进程同时要操作同一个资源时,将会导致数据错乱的问题

    解决方案1:

    加join, ​ 弊端 1.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了 ​ 2.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的

    解决方案2:

    就是给公共资源加锁,互斥锁 ​ 互斥锁 互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)

    锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行

    锁和join的区别:

    1.join是固定了执行顺序,会造成父进程等待子进程 锁依然是公平竞争谁先抢到谁先执行,父进程可以做其他事情

    2.最主要的区别: join是把进程的任务全部串行 锁可以锁任意代码 一行也可以 可以自己调整粒度

    #  当多个进程操作同一份数据的时候 会造成数据的错乱
    #         这个时候必须加锁处理
    #             将并发变成串行
    #                 虽然降低了效率但是提高了数据的安全
    #             注意:
    #                 1.锁不要轻易使用 容易造成死锁现象
    #                 2.只在处理数据的部分加锁 不要在全局加锁
    #
    #         锁必须在主进程中产生 交给子进程去使用
    
    注意1:  不要对同一把执行多出acquire 会锁死导致程序无法执行  一次acquire必须对应一次release
    
    ```python
     l = Lock()
     l.acquire()
     print("抢到了!")
     l.release()
     l.acquire()
     print("强哥毛线!")
    ```
    
    注意2:想要保住数据安全,必须保住所有进程使用同一把锁
    
    
    
    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()
    View Code
  • 相关阅读:
    「UVA12293」 Box Game
    「CF803C」 Maximal GCD
    「CF525D」Arthur and Walls
    「CF442C」 Artem and Array
    LeetCode lcci 16.03 交点
    LeetCode 1305 两棵二叉搜索树中的所有元素
    LeetCode 1040 移动石子直到连续 II
    LeetCode 664 奇怪的打印机
    iOS UIPageViewController系统方法崩溃修复
    LeetCode 334 递增的三元子序列
  • 原文地址:https://www.cnblogs.com/tfzz/p/11329321.html
Copyright © 2011-2022 走看看