目录
回顾
1.粘包问题:
1) 无法确认发送数据的大小。
2) 短时间内发送多次数据量小并且间隔时间短的数据会一次性打包发送。
2.struct
可以将一个很长的数据,压缩成固定的长度,比如4.
3.解决粘包问题:
1.通过struct模块弄一个报头。
可以把字典压缩成一个报头,发送给服务端。
2.服务端接收到报头后解压缩,获取真实字典数据长度。
接收字典真实数据。
注意: 字典里可以携带即将发送的数据描述信息,以及数据的真实大小。
4.上传大文件
1.客户端发送字典到服务端
2.服务端接收到字典后,利用字典内文件的名字,以该名字创建文件名。
3.字典内包含着大文件的数据大小,然后循环一点一点接收。
5.UDP:
- 不需要建立连接
- 没有粘包问题
- 发送数据不需要等待返回接收成功
- 数据不安全,易丢失
6.socketserver
基于socket模块封装而成,内置的theadingTcp(),可以支持多个用户同时连接服务端。
7.FTP:
客户端: start
服务端: start
操作系统发展史
1)穿孔卡片:
一个计算机机房,一次只能被一个卡片使用。
缺点:
CPU利用率最低。
2)联机批处理系统
支持多用户去使用一个计算机机房。
3) 脱机批处理系统
高速磁盘:
提高文件的读取速度。
优点:
提高CPU的利用率
3)多道技术(基于单核情况下研究):
- 单道:
多个使用使用CPU时是串行。
- 多道技术:
空间上的复用(*******):
一个CPU可以提供给多个用户去使用。-
时间上的复用(*******):
切换 + 保存状态IO操作:
input()
print()
time.sleep(3)1) 若CPU遇到IO操作,会立即将当前执行程序CPU使用权断开。
优点:
CPU的利用率高。2) 若一个程序使用CPU的时间过长,会立即将当前执行程序CPU使用权断开。
缺点:
程序的执行率降低。
- 并发与并行:
并发: 指的是看起来像同时在运行,多个程序不停 切换 + 保存状态。
并行: 真实意义上的同时运行,在多核(多个CPU)的情况下,同时执行多个程序。
进程
-
程序与进程
- 程序: 一堆代码。
- 进程: 一堆代码运行的过程。- 进程调度: 当代操作系统调度: 时间片轮转法 + 分级反馈队列 1)先来先服务调度: a,b程序,若a程序先来,先占用CPU。 缺点: 程序a先使用,程序b必须等待程序a使用cpu结束后才能使用。 2)短作业优先调度: a,b程序,谁的用时短,先优先调度使用cpu。 缺点: 若程序a使用时间最长,有N个程序使用时间短, 必须等待所有用时短的程序结束后才能使用。
3) 时间片轮转法
CPU执行的时间1秒中,加载N个程序,要将1秒等分成多N个时间片。
4) 分级反馈队列
将执行优先分为多层级别。
- 1级; 优先级最高。
- 2级: 优先级第二,以次类推。
- 3级
....
- 进程的三个状态:
就绪态:
所有进程创建时都会进入就绪态,准备调度。运行态:
调度后的进程,进入运行态。阻塞态:
凡是遇到IO操作的进程,都会进入阻塞态。
若IO结束,必须重新进入就绪态。
同步和异步
指的是提交任务的方式。
同步:
若有两个任务需要提交,在提交第一个任务时,
必须等待该任务执行结束后,才能继续提交并执行第二个任务。异步:
若有两个任务需要提交,在提交第一个任务时,
不需要原地等待,立即可以提交并执行第二个任务。- 阻塞与非阻塞:
阻塞:
阻塞态。遇到IO一定会阻塞。非阻塞:
就绪态
运行态
同步和异步,阻塞和非阻塞是同一个概念吗?
强调: 不是同一个概念,不能混为一谈!
最大化提高CPU的使用率:
尽可能减少不必要的IO操作。
import time
def test():
# IO操作
# time.sleep(3)
# 计算操作
num = 1
for line in range(1000000000000000000000000):
num += 1
if __name__ == '__main__':
test()
print('hello tank')
# from multiprocessing import Process
# import time
'''
创建进程方式一:
'''
# # 1.定义一个任务
# def task(name):
# print(f'{name}的任务开始执行')
# time.sleep(1)
# print(f'{name}的任务已经结束')
#
#
# # 在linux/mac系统下不会报错
# # p = Process(target=task, args=('jason',))
#
# if __name__ == '__main__':
# # target=执行函数的地址
# p = Process(target=task, args=('jason',))
# # 向操作系统提交创建进程的任务
# p.start()
# print('主进程')
'''
windows:
创建子进程,windows会将当前父进程代码重新加载执行一次。
linux/mac:
会将当前父进程代码重新拷贝一份,再去执行。
'''
# 创建进程方式二:
# 1.自定义一个类,并继承Process
# class MyProcess(Process):
#
# # 父类的方法
# def run(self):
# print('任务开始执行')
# time.sleep(1)
# print('任务已经结束')
#
#
# if __name__ == '__main__':
# p = MyProcess()
# p.start()
# # p.start()
# print('主进程')
'''
join方法: 用来告诉操作系统,让子进程结束后,父进程再结束。
'''
# from multiprocessing import Process
# import time
#
#
# def task(name):
# print(f'{name} start...')
# time.sleep(2)
# print(f'{name} over..')
#
#
# if __name__ == '__main__':
# p = Process(target=task, args=('jason', ))
# p.start() # 告诉操作系统,开启子进程
# p.join() # 告诉操作系统,等子进程结束后,父进程再结束。
# print('主进程')
from multiprocessing import Process
import time
def task(name, n):
print(f'{name} start...')
time.sleep(n)
print(f'{name} over..')
if __name__ == '__main__':
p1 = Process(target=task, args=('jason', 1))
p2 = Process(target=task, args=('egon', 2))
p3 = Process(target=task, args=('sean', 3))
p1.start()
p2.start() # 告诉操作系统,开启子进程
p3.start() # 告诉操作系统,开启子进程
p1.join() # 告诉操作系统,等子进程结束后,父进程再结束。
p2.join()
p3.join()
print('主进程')
'''
进程间数据相互隔离:
主进程与子进程会产生各自的名称空间。
'''
from multiprocessing import Process
x = 100
def func():
print('执行func函数...')
global x
x = 200
if __name__ == '__main__':
p = Process(target=func)
p.start()
print(x)
print('主')
'''
current_process().pid: 获取子进程号
os.getpid(): 获取主进程pid号
cmd中查看进程号: tasklist |findstr 进程号
进程号回收的两种条件:
1.join,可以回收子进程与主进程。
2.主进程正常结束,子进程与主进程也会被回收。
os.getppid()
'''
from multiprocessing import Process
from multiprocessing import current_process
import os # 与操作系统交互
import time
def task(name):
print(f'{name} start...', current_process().pid)
time.sleep(1)
print(f'{name} over..', current_process().pid)
if __name__ == '__main__':
p = Process(target=task, args=('jason', ))
p.start() # 告诉操作系统,开启子进程
# 判断子进程是否存活
print(p.is_alive())
# 直接告诉操作系统,终止 子进程
p.terminate()
time.sleep(0.1)
# 判断子进程是否存活
print(p.is_alive())
p.join() # 告诉操作系统,等子进程结束后,父进程再结束。
print('主进程', os.getpid())
print('主主进程', os.getppid())
time.sleep(100)
进程号回收的两种条件:
1.join,可以回收子进程与主进程。
2.主进程正常结束,子进程与主进程也会被回收。
僵尸进程与孤儿进程
僵尸进程:
指的是子进程已经结束,但PID号还存在,未销毁.
缺点:
占用PID号,占用操作系统资源.
孤儿进程:
指的是子进程还在执行,但父进程意外结束.
操作系统优化机制:
提供一个福利院,帮你回收没有父亲的子进程.
守护进程
指的是主进程结束后,该主进程产生的所有子进程跟着结束,并回收.
from multiprocessing import Process
from multiprocessing import current_process
import time
def task(name):
print(f'{name} start...', current_process().pid)
time.sleep(5)
print(f'{name} over..', current_process().pid)
print(f'管家{name}')
if __name__ == '__main__':
p1 = Process(target=task, args=('jason', ))
# 添加守护进程参数
p1.daemon = True # True代表该进程是守护进程
p1.start()
print(f'egon 驾鹤西去...')