Python Day 32 进程和程序的区别、阻塞 非阻塞 并行 并发、进程的三种状态、进程的创建和销毁、python中两种方式实现多进程、进程间内存相互隔离、join函数孤儿进程与僵尸进程

  ##内容回顾

# UDP协议  

​    用户数据报协议,是OSI模型中属于传输层的协议 

​    提供,不可靠的,不要求顺序的,数据量小的,速度快的传输服务 

​    不可靠:

​        发送完成后不需要确认信息 并且立即删除缓存中的数据 

​    不要求顺序:

​        当一个数据较大时 会分为多个数据报来传输,对方无法获知数据的顺序,以及是否完整

​    数据量较小的:

​        数据越大丢包的可能性越高 ,建议的数据量不要超过1472

​    速度快:

​        相对于TCP而言快很多 不需要确认信息 ,也不需要建立链接 

# 通讯流程

​    如果TCP比喻为手机打电话的过程 那么UDP可以看做是对讲机   

​    1.买机器    创建UDP的socket 

​    2.固定频道    bind一个ip和端口

​    3.收发数据      recvfrom   sendto 

​    

​    接收

​    1.买机器    创建UDP的socket 

​    2.收发数据      recvfrom   sendto 

​        注意 不能先收    要收数据 必须明确端口号  没有端口号是不可能使用网络服务的 



​    

###TCP  与 UDP 的其他区别

1.没有连接  

2.不会粘包     每次发送都是一个独立的数据包    



TCP 对数据完整性要求较高 : 在线支付  ,文字信息 

 UDP: 对数据不要求完整性 但是要快 :  视频 语音 游戏  

# DNS 

域名解析服务器  

域名 就是一串有规律的字符串  ,用于绑定IP,目的是为了方便记忆 

域名解析服务器    就是帮你将域名转换为ip地址  

本质就是一个数据库  里面存的就是域名和ip对应关系   

一台机器性能有限

分为 

​    根域名服务器        只存储定义域名服务器的信息  

​    顶级域名服务器 只存储二级域名服务器的信息  

​    二级域名服务器    二级存三级 

​    三级域名   三级可以存四级  通常直接存储具体的ip信息  

​    .....................

​    本地DNS  用于加速解析    



###自己搭建DNS 的作用
1.CDN     内容分发网络       就是在你的周围建立更多镜像服务    

​    2.集群   

# 操作系统

也是一个软件, 

​    受保护的不能随意修改  

​    代码量巨大  内核在500万以上 

​    长寿 ,一旦完成一般不改 

​    linux是脱袜子  将(shell 保留解释权!)  移植到minux上 结合产生的 

###操作系统的作用:

1.将复杂丑陋的硬件细节隐藏起来,提供了简单的调用接口 

2.将应用程序对于硬件的竞争变的有序  



###操作系统发展史  
1.第一带计算机   真空管和穿孔卡片  没有进程 没有操作系统   

​    2.第二代计算机  7094 1401    晶体管  批处理系统 

​        输入输出  以及计算设备 不能互联  需要人参与    一批一批的处理   开发效率慢  并且串行执行

​    3.第三代计算机    集成电路 与多道技术 

​        多终端联机  spooling      同一台机器既能进行科学计算  又能做字符处理       通用计算机

​        多道技术   解决串行导致的效率低下问题

​        多用户终端    可以同时为多个用户提供服务  每个用户以为自己独享一台计算机   

​    4.第四代   个人电脑

​        大规模使用了集成电路,大多都提供了GUI界面  

# 多道技术   

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

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

## 关键技术

### 空间复用

指的是 同一时间 内存中加载多个不同程序数据,

每个进程间内存区域相互隔离,物理层面的隔离  

### 时间复用       切换 + 保存

    # 切换条件:

    1.一个进程执行过程中遇到了IO操作  切换到其他进程

    2.运行时间过长,会被操作系统强行剥夺执行权力   

单纯的切换不够,必须在切换前保存当前的状态,以便于恢复执行  



# 进程

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

进程来自于操作系统  

  ##多进程

# 进程和程序的区别  
“”“

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

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

一旦运行就产生了进程    

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

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

”“”

# 阻塞  非阻塞   并行  并发   (重点)
“”“

阻塞 : 程序遇到io操作是就进入了阻塞状态     

​    本地IO input      print     sleep    read  write       

​    网络IO recv  send

非阻塞: 程序正常运行中 没有任何IO操作   就处于非阻塞状态  

阻塞 非阻塞 说的是程序的运行状态  

并发: 多个任务看起来同时在处理 ,本质上是切换执行     速度非常快    

并行: 多个任务真正的同时执行    必须具备多核CPU  才可能并行  

并发  并行  说的是 任务的处理方式

”“”

  ##进程的三种状态

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

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

  ##程序员的永恒话题

提高效率

根本方法就是让程序尽可能处于运行状态

减少IO  尽可能多占用CPU时间     

缓冲区就是用于减少IO操作的

  ##进程的创建和销毁(了解)

### 进程的创建

但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,进程就已经存在。

  而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式创建新的进程

1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)

### 进程的销毁

1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
2. 出错退出(自愿,python a.py中a.py不存在)
3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)
4. 被其他进程杀死(非自愿,如kill -9### 进程的层次结构

无论UNIX还是windows,进程只有一个父进程,不同的是:

1. 在UNIX中所有的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员。
2. 在windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(**称为句柄**),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了。

  ##python中实现多进程

“”“
在一个应用程序中可能会有多个任务需要并发执行,但是对于操作系统而言,一个进程就是一个任务,CPU会从上往下依次执行代码,当代码中遇到IO操作时,操作系统就会剥夺CPU执行权给其他应用程序,这样对于当前应用程序而言,效率就降低了,如何使得程序既能完成任务又不降低效率呢?答案就是让把当前程序中的耗时操作交給子进程来完成,如此当前应用程序可以继续执行其他任务!
”“”

#python中开启子进程的两种方式

#方式一:直接实例化Process  ,将要执行任务用target传入
from multiprocessing import Process
import os
import time
# 为什么要子进程   当出现一些耗时较长的操作时 会导致程序进入阻塞状态  二无法执行其他代码
# 这时候就可以开启子进程把任务交给他

def task(name):
    print(" name %s 子进程run!" % name)
    # print("son is :%s" % os.getpid())
    # print("father is :%s" % os.getppid())
    time.sleep(3)
    print("子进程 over!")


if __name__ == '__main__':
    print("father :%s" % os.getpid())
    p = Process(target=task,args=("rose",))
    p.start() # 开启子进程   本质是向操作系统发送请求 让它启动进程    通常不可能立即开启
    print("任务结束!")

"""
windows  和  linux 开启进程的方式不同 
首先相同之处都是 需要将数据copy一份给子进程   这样子进程才知道要干什么  
linux 会将父进程的所有数据 完全copy    
windows  会copy 一部分数据   同时会导入py文件来执行   这样一来递归开进程    
linux 拿到父进程知道代码位置 继续执行   
建议都加上判断  可以保证两个平台都能用  

记住:
开启进程的代码 都把它放到  if __name__ == "__main__": 中即可


"""


#方式二:继承Process类 ,覆盖run方法  将任务放入run方法中 (重点掌握) 
import os
from multiprocessing import  Process
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name
    # 继承Procee覆盖run方法将要执行任务发到run中
    def run(self):
        print(self.name)
        print("子进程 %s running!" % os.getpid())
        print("子进程 %s over!" % os.getpid())

if __name__ == '__main__':
    # 创建时 不用再指定target参数了
    p = MyProcess("rose")
    p.start()
    print("父进程over!")

  ##进程间内存相互隔离

from multiprocessing import Process
import time
name = "青椒"
def task():
    global name
    name = "rose"
    print("改完了!")
    print("子进程的%s" % name)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    time.sleep(2)
    print(name)

  ##join函数

“”“
调用start函数后的操作就由操作系统来玩了,至于何时开启进程,进程何时执行,何时结束都与应用程序无关,所以当前进程会继续往下执行,join函数就可以是父进程等待子进程结束后继续执行,即用于提高子进程优先级 ,使得父进程等待子进程结束  
”“”

#案例
"""
    当你开启了一个子进程 并且给他一个任务  如果你希望知道这个任务什么时候完成 那就需要等待

"""
import time,os
from multiprocessing import Process
# def task(i):
#     # print(" %s 买烟去了" % i)
#     time.sleep(3)
#     print("%s 买完了!" % i)
#
# if __name__ == '__main__':
#     # p = Process(target=task)
#     # p.start()
#     # # time.sleep(5)
#     # p.join() # 等待子进程执行完毕   将子进程的优先级提高
#     #
#
#
#
#     for i in range(10):
#         p = Process(target=task,args=(i,))
#         p.start()  # 进程启动顺序  与start无关   主要看操作系统先切换谁
#         # p.join()
#
#     p.join()  # 最后一个
#
#
#     print("over!")


def task(i):
    # print(" %s 买烟去了" % i)
    time.sleep(i)
    print("%s 买完了!" % i)

if __name__ == '__main__':
    strat_time = time.time()
    p1 = Process(target=task,args=(1,))
    p2 = Process(target=task,args=(2,))
    p3 = Process(target=task,args=(3,))

    p1.start()
    p2.start()
    p3.start()

    p3.join() #3
    p2.join()
    p1.join()


    end_time = time.time()
    print(end_time - strat_time)
    print("over!")


#案例2
from multiprocessing import Process
import time,random
x=1000
def task(n):
    print('%s is runing' %n)
    time.sleep(n)
if __name__ == '__main__':
    start_time=time.time()
    p1=Process(target=task,args=(1,))
    p2=Process(target=task,args=(2,))
    p3=Process(target=task,args=(3,))
    p1.start()
    p2.start()
    p3.start()
    p3.join() #3s
    p1.join()
    p2.join()
    print('主',(time.time() - start_time))
    start_time=time.time()
    p_l=[]
    for i in range(1,4):
        p=Process(target=task,args=(i,))
        p_l.append(p)
        p.start()
    for p in p_l:
        p.join()
   
    print('主',(time.time() - start_time))

  ##Process对象常用属性

扫描二维码关注公众号,回复: 6318887 查看本文章
from multiprocessing import  Process
import time,os
def task():
    print("121121")
    # time.sleep(10)
    # print("over")
    # print(os.getppid())
    exit(1000)

if __name__ == '__main__':
    p = Process(target=task,name="rose")
    p.start() # 懒加载优化机制  如果没有调用start 那么该对象将不会被创建
    time.sleep(1)
    # p.join() # 等待子进程结束
    # p.terminate()  # 终止进程
    # print(p.name)  # 进程的名称
    # print(p.is_alive()) #是否存活
    # p.terminate() # 与start一样 都是给操作系统发送指令 所以会有延迟
    # print(p.is_alive())
    # print(p.pid)
    # print(p.exitcode) # 获取退出码

  ##孤儿进程与僵尸进程

## 孤儿进程

指的是,父进程先结束 ,而子进程还在运行着, 

孤儿进程无害,有 其存在的必要性 

例如:qq开启了浏览器,qq先退出了  浏览器应该继续运行  

孤儿进程会被操作系统接管    



## 僵尸进程

值得是,子进程已经结束了,但是操作系统会保存一些进程信息,如PID,运行时间等,此时这个进程就称之为僵尸进程  

僵尸进程如果太多将会占用大量的资源,造成系统无法开启新新进程 

linux 中有一个wai/waitpid 用于父进程回收子进程资源

python会自动回收僵尸进程  

  

猜你喜欢

转载自www.cnblogs.com/liangzhenghong/p/10956994.html