##内容回顾
# 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
import time,random
x=1000
def task(n):
print('%s is runing' %n)
time.sleep(n)
print('%s is runing' %n)
time.sleep(n)
if __name__ == '__main__':
start_time=time.time()
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()
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()
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))
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对象常用属性
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会自动回收僵尸进程