网络并发编程的本质就是为了提升CPU的工作效率.
目录
操作系统发展史
计算机的三大核心硬件是: CPU, 内存, 硬盘. 其中CPU是整个计算机执行效率的核心
操作系统经历了三个时代;
1.穿孔卡片时代
CPU的利用率非常低, 优点是一个人独占计算机.
2.联机批处理系统
缩短了录入数据的时间,提升了CPU利用率
3.脱机批处理系统
是现代计算机的雏形, 提升了CPU的利用率
多道技术
其前提是一个CPU
单道技术是所有的程序排队执行, 总耗时是所有程序耗时之和.
多道技术是计算机利用空闲时间提前准备好一些数据,提高效率, 总耗时较短.
多道技术的特点是切换+保存状态
1.CPU在两种状态下会切换去执行其他操作
1.程序自身进入IO操作[IO操作: 输入输出操作, 获取用户输入, 读取文件,保存文件,time.sleep()等
2. 程序长时间占用CPU.
2. 保存状态 每次切换之前都要记录下当前执行的状态,之后切回来基于当前状态继续执行.
进程理论
进程: 正在被运行的程序
进程的调度算法:
1.先来先服务 >>> 对耗时较短的程序不友好
2.短作业优先调度 >>> 对耗时长的程序不友好
3.时间片轮转法+多级反馈队列
将固定的时间均分成很多份,所有的程序来了都平分一份 >>> 分配多次之后如果还有程序需要运行, 则将其分到下一层 >>> 越往下表示程序总耗时越长,每次分的时间片越多则优先级越低.
进程的并行与并发
并行: 多个进程同时执行 , 需要有多个CPU
并发:多个进程看上去像是同时执行就可以称之为并发, 单个CPU完全可以实现并发的效果, 如果是并行那么肯定也属于并发. >>>> 描述一个网站很厉害能同时服务很多人>>>> 这个网站能够支持14亿并发量(高并发) >>> 国内最厉害的网站>>>12306
进程三状态
就绪态: 所有程序被运行期都要经过就绪态(准备状态)
运行态:运行过程中如果出现了IO操作,则进入阻塞态, 如果时间片段用完则继续进入就绪态
阻塞态: 想要进入运行态就必须经过就绪态
同步和异步
用于描述人物的提状态
同步: 提交完任务后原地等待任务结束, 不做任何事.
异步: 提交完任务后不原地等待直接去做其他事情, 有了结果自动提醒.
阻塞与非阻塞
用于描述进程的执行状态
阻塞为阻塞态
非阻塞为就绪态或者运行态
同步异步与阻塞非阻塞
同步阻塞: 排队,并且在队伍中做什么都不做
同步非阻塞; 排队, 在排队过程中做一些事情
异步阻塞: 取号, 在旁边等待被叫号,期间什么也不做
异步非阻塞: 取号,在旁边等待叫号,期间做想做的事.
其中异步非阻塞状态下 CPU利用率最高.
创建进程的两种方式
1.双击桌面程序图标
2.代码创建
from multiprocessing import Process
import time
def task(name):
print(f'{name}开始运行')
time.sleep(3)
print(f'{name}运行结束')
if __name__ == '__main__':
p = Process(target=task,args=('lili',)) # 创建一个进程对象
p.start() # 告诉操作系统创建一个进程(异步操作)
# task('lili') # 普普通通的函数调用是 同步操作
print('主进程')
""" 创建进程的代码在不同的操作系统中, 底层原理有区别.
在Windows中, 创建进程类似于导入模块
if __name__ == '__main__': 启动脚本在MAC,LINUX中创建进程类似于直接copy,不需要启动脚本, 但是为了兼容性, 也可以使用."""`
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
print(f'{self.name}开始运行')
time.sleep(3)
print(f'{self.name}结束运行')
if __name__ == '__main__':
obj = MyProcess('lili')
obj.start()
print('主进程')
**创建进程的方式和创建现成的方式一致.**
同一进程下线程间数据共享
我们将进程比作车间, 线程比作流水线, 那么同意车间内的资源是可以被不同流水线间共享的.
from threading import Thread
money = 1000
def func():
global money
money = 666
t = Thread(target=func)
t.start()
t.join() # 确保线程运行完毕 再查找money 结果更具有说服性
print(money)
进程join方法
join主进程等待子进程运行结束之后在运行
>>> 直接在主进程代码里添加time.sleep()是不合理的, 因为无法准确把我子进程的执行时间
使用join方法就会变得合理很多
from multiprocessing import Process
import time
def task(name):
print(f'{name}正在运行')
time.sleep(3)
print(f'{name}结束运行')
if __name__ == '__main__':
p1 = Process(target=task,args=('lili',1))
p2 = Process(target=task,args=('pop',2))
p3 = Process(target=task,args=('kim',3))
start_time = time.time()
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
end_time = time.time() - start_time
print('总耗时:%s' %end_time)
print('主进程')
线程join方法
主线程等到子线程运行结束之后再运行
from threading import Thread
import time
def task():
print('正在执行')
time.sleep(3)
print('运行结束')
t = Thread(target=task)
t.start()
t.join()
print('主线程')
进程间默认数据隔离
多个进程数据彼此之间默认相互隔离
如果真的要交互,需要借助于'管道'或者'队列'
from multiprocessing import Process
money = 100
def task():
global money
money = 666
print('子进程打印的money', money)
if __name__ == '__main__':
p = Process(target=task)
p.start()
p.join()
print('父进程打印的money', money)
IPC机制
1.主进程与子进程通信
2.子进程与子进程通信
from multiprocessing import Queue,Process
def procedure(q):
q.put('子进程procedure往队列里添加了数据')
def consumer(q):
print('子进程consumer从队列里获取数据',q.get())
if __name__ == '__main__':
q = Queue() # 在主进程中产生q对象,确保所有的子进程使用的是相同的q
p1 = Process(target=procedure, args=(q,))
p2 = Process(target=consumer, args=(q,))
p1.start()
p2.start()
print('主进程')
生产者消费者模型
生产者: 产生数据
消费者: 处理数据
进程相关方法
查看进程号
from multiprocessing import current_process
import os
current_process().pid
os.getpid()
os.getppid()
销毁子进程
p1.terminate()
判断进程是否存活
p1.is_alive()
线程相关方法
1.进程号
同一个进程下开设的多个线程拥有相同的进程号
2.线程名
from threading import Thread, current_thread
current_thread().name
主:MainThread 子:Thread-N
3.进程下的线程数
active_count()
守护进程
伴随着守护对象的存活而存活 死亡而死亡
from multiprocessing import Process
import time
def task(name):
print('用户a:%s存活' % name)
time.sleep(3)
print('用户a:%s消失' % name)
if __name__ == '__main__':
p = Process(target=task, args=('基佬',))
# p.daemon = True # 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
p.start()
p.daemon = True # 必须在start之前执行
print('主进程结束!!!')
守护线程
守护线程伴随着被守护的线程的结束而结束
from threading import Thread
import time
def task():
print('子线程运行task函数')
time.sleep(3)
print('子线程运行task结束')
t = Thread(target=task)
# t.daemon = True
t.start()
# t.daemon = True
print('主线程')
进程下所有的非守护线程结束 主线程(主进程)才能真正结束!!!
僵尸进程与孤儿进程
僵尸进程: 进程已经运行结束,单数相关资源并没有完全清空, 需要父进程参与回收
孤儿进程: 父进程意外死亡,子进程正常运行,操作系统会自动回收相关资源.
本文全是理论, 只为科普一些基本的概念.