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
  • 相关阅读:
    用JS实现气泡效果
    如何判断浏览器JS代码
    你是怎么看完《JavaScript权威指南》《JavaScript高级程序设计》等这类厚书的?
    CSS3技巧:fit-content水平居中
    捋一捋JavaScript对象的理解
    js 判断数据类型的几种方法
    给想转行学习web前端的朋友提些学习建议及学习路线
    sentry 9.1.1docker版onepremise过程记录
    python内置函数all使用的坑
    centos7.2自带的php5.4升级为5.6
  • 原文地址:https://www.cnblogs.com/tfzz/p/11329321.html
Copyright © 2011-2022 走看看