计算机操作系统发展史
#多道技术
  1.空间复用:
    同一时间在内存中存放多个程序 内存相互隔离
  2.时间复用:
    CPU在遇到IO时切换到另一个程序
  可以实现并发
    切换+保存状态


#进程理论:
进程和程序的区别:
    程序是什么?
        本质就是一堆代码文件
        一个程序正在被操作系统读取操作并执行 就变成了进程
一个程序只能有一个进程嘛?
    可以 启动一次就产生一个进程 当然可以用代码控制是否允许多进程

#进程的概念起源于操作系统,进程是操作系统最核心的概念,操作系统其它所有的概念都是围绕进程来

    操作系统理论:
        1. 操作系统是什么?
            操作系统是一个协调\管理\控制计算机硬件资源与应用软件资源的一段控制程序
            有两大功能:
                1. 将复杂的硬件操作封装成简单的接口给应用程序或者用户去使用
                2. 将多个进程对硬件的竞争变得有序

    操作系统发展史
        并发: 多个任务看起来是同时运行的
        串行:一个任务完完整整地运行完毕,才能运行下一个任务

        多道技术:(复用=>共享/共用)
            1. 空间上的复用:多个任务复用内存空间
            2. 时间上的复用:多个任务复用cpu的时间
                1. 一个任务占用cpu时间过长会被操作系统强行剥夺走cpu的执行权限:比起串行执行反而会降低效率
                2. 一个任务遇到io操作也会被操作系统强行剥夺走cpu的执行权限:比起串行执行可以提升效率

启动进程的方式
    1.系统初始化 会产生一个根进程
    2.用户的交互请求 鼠标双击某个程序
    3.在一个进程中 发起了系统调用启动了另一个进程******
    4.批处理作业开始 某些专用计算机可能还在使用

每个操作系统创建进程的方式不同
    unix <  centos  mac  linux
    linux 下创建进程 会直接将父进程的所有数据复制一份给子进程
    windows 创建进程时 子进程会加载父进程的字节码(没有多余符号)

开启子进程:
    子进程会把父进程的内容加载一份到自己的内存空间,两个进程之间的数据是互不干涉的
    在开启子进程时,子进程开启写在if __name__ == '__main__':开启否则会重复开启新的
    子进程无法正常运行
    主进程和子进程是处于并发编程的,没有执行顺序一说
    我们的代码只负责通知操作系统创建进程 创建完就继续其他代码
    系统什么时候创建完成,什么时候执行代码是我们无法预知的

    开启子进程以及父进程在子进程后执行的例子:
        from  multiprocessing import Process
        import time,os
        def  task(name):
            print("这是一个程序%s"%name)
            time.sleep(4)
            print("结束时候%s"%name)
        if __name__ == '__main__':
            p=Process(target=task,args=("egon",))
            p.start()
            print("主程序pid %s,主程序父pid %s"%(os.getpid(),os.getppid()))
            print("zi进程pid %s"%p.pid)
            #p.join主进程会等子进程结束
            p.join(2)#主进程会等子进程2秒后再继续执行
            print("这是主")

    验证进程间是并发执行例子:
    from  multiprocessing import Process
    import time,os
    def  task(name):
        print("这是一个程序%s"%name)
        time.sleep(4)
        print("结束时候%s"%name)
    if __name__ == '__main__':
        start=time.time()
        ps=[]
        for i in range(1,3):
            p=Process(target=task,args=(i,))
            p.start()
            ps.append(p)
        print("主程序pid %s,主程序父pid %s"%(os.getpid(),os.getppid()))
        print("zi进程pid %s"%p.pid)
        for p in ps:
            p.join()
        print("这是主",time.time()-start)

第二种开启子进程方式继承的是run函数:
    from multiprocessing import Process
    #记住语法
    class MyProcess(Process):
        #当进程被执行时 其实执行的就是run函数
        def run(self):#你要做的事情放在run中
            print("run被执行了")
    if __name__ == '__main__':
        mp=MyProcess()
        mp.start()

进程对象常用的属性:
    if __name__ == '__main__':
        p = Process(target=task, args=("egon",))
        p.start()
        print("主程序pid %s,主程序父pid %s" % (os.getpid(), os.getppid()))
        print("zi进程pid %s" % p.pid)
        # p.join主进程会等子进程结束
        p.join()  # 主进程会等子进程2秒后再继续执行 使父进程让出cou执行权
        print(p.name)#进程名称
        print(p.pid)#h获取这个子进程的id
        p.terminate()#结束字进程
        time.sleep(2)
        print(p.is_alive())#判断进程是否存活,会有一点点时间延迟
        print("这是主")

        #p这个进程的父进程 是 “执行文件”这个进程
        import os
        print(os.getpid())#当前自己进程的id
        print(os.getppid())#pycharm的进程id

        #父进程如何获取子进程中的数据,跨进程读取

僵尸进程和孤儿进程
    僵尸进程:一个进程任务执行完就死亡了 但是操作系统不会立即将其清理 为的是
        开启这个子进程的父进程可以访问的这个子进程的id
        这样的完成任务的但未被系统清理的僵尸进程 越少越好

    孤儿进程:一个父进程已经死亡 可然而他的子孙进程 还在执行着 这时候操作系统
        会接管这些孤儿进程。它们是对系统无害的