一.操作系统理论
计算机的硬件组成
- 主板 固化(寄存器, 是直接和cpu进行交互的一个硬件)
- cpu 中央处理器: 计算 (数字计算和逻辑计算) 和控制 (控制所有硬件协调工作)
- 存储 硬盘, 内存
- 输入设备 键盘, 鼠标, 话筒
- 输出设备 显示器, 音箱, 打印机
- 早期的计算机是以计算为核心的
- 现在的计算机是以存储为核心的
- 第一代计算机: 电子管计算机, 及其耗电, 体积庞大, 散热量特别高
- 第二代计算机: 晶体管计算机
- 第三代计算机: 白色大头计算机, 集成电路计算机. 一个板子固化几十到上百个小硬件
- 第四代计算机: 大型集成电路计算机, 一个板子可以达到固化十万个硬件
- 第五代计算机: 甚大型集成电路计算机
计算机的操作系统
- 操作系统是一个软件, 是一个能直接操纵硬件的一个软件,微软研发的windows系统
- 人工时代: 穿孔卡带, 每个人都能在一段时间内独享计算机所有资源
- 脱机时代: 完全将人和及其隔离开来
- 单道批处理系统: 内存中允许存放一道作业
- 多道批处理系统: 内存中允许存放多道作业
- 分时系统: 将cpu和执行划分时间片, 每个程序以时间片为单位去执行
- 实时系统: 一般比较少见, 主要用于军事和工业生产上
- 操作系统的目的: 让用户用起来更加轻松, 高可用, 低耦合
语言的发展史
- 计算机识别的二进制, 机器语言, 由0 和 1 组成代码
- 汇编语言, add ,n,m
- 高级语言: 面向过程(C) 面向对象语言(C++, java, python, php)
- os(操作系统)
- dos系统 纯编程系统 单用户单任务
- windows系统 单用户多任务(早期的windows)
- unix系统 多用户多任务
- 计算机识别的二进制, 机器语言, 由0 和 1 组成代码
操作系统的作用
- 封装所有硬件接口, 让各种用户使用电脑更加轻松
- 是对计算机内所有资源进行合理的调度和分配
二.进程
- 进程的理论
- .sh shell脚本文件
- .out linux系统中的可执行文件
- .bat 批处理脚本文件
- .lib 库文件
- .dll 库文件
- .exe 可执行文件, 双击能直接运行的文件
- 进程
- 是指正在执行的程序,是程序执行过程中的一次 指令, 数据集等的集合
- 也可以叫做程序的一次执行过程
- 进程是一个动态的概念
- 进程由三大部分组成: 代码段, 数据段, PCB: 进程管理控制
- 进程的三大基本状态:
- 就绪状态: 已经获得运行需要的所有资源, 处理cpu
- 执行状态: 已经获得了所有的资源包括cpu, 处于正在运行
- 阻塞状态: 因为各种原因, 进程放弃了cpu, 导致进程无法继续执行,此时进程处于内存中,继续等待获取cpu
- 进程的一个特殊状态
- 挂起状态: 是指因为各种原因,进程放弃了cpu, 导致进程无法继续执行,此时进程被踢出内存
- multiprocessing 内置模块, 是python提供, 主要用于多线程编程
三.多进程
1.名词解释
同步和异步关注的是消息通信机制
并行: 并行是指两者同时执行, 比如有两条车道,在某一时间点, 两条车道上都有车在跑(资源够用,比如三个线程, 四核的CPU) 指两件或多件事在同一时间点执行
并发: 指两件或多件事在同一时间间隔同时执行
区别: 并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行, 这就要求必须有多个处理器
并发是从宏观上,在一个时间段上可以看出是同时执行的, 比如一个服务器同时处理多个session
早起单核CPU时候, 对于进程也是微观上串行(站在cpu角度看), 宏观上并行(站在人的角度看就是同时有很多程序执行)
同步: 所谓同步就是一个任务的完成需要依赖另外一个任务时, 只有等待被依赖的任务完成时,依赖的任务才能算完成,这是一种可靠的任务序列.要么都成功. 要么都失败, 两个任务的状态可以保持一致
异步: 所谓异步是不需要等待依赖的任务完成, 只是通知被依赖的任务要完成什么工作, 依赖的任务也立即执行, 只要自己完成了整个任务就算完成了, 至于被依赖的任务最重是否真正完成, 依赖它的任务无法确定, 所以它是不可靠任务序列
阻塞: 阻塞是当请求不能满足的时候将进程挂起
非阻塞: 非阻塞是不会阻塞当前进程,非阻塞调用指在不能立刻得到结果之前也会立刻返回,同时该函数不会阻塞当前线程。
阻塞和非阻塞针对的是进程或线程
2.进程的两种开启方法
(1) p = Process(target = func, args (,))
from multiprocessing import Process
import time
import os
def func(i):
time.sleep(1)
print('这里是%s儿子进程%s,父进程是%s' % (i, os.getpid(), os.getppid()))
if __name__ == '__main__':
for i in range(2):
p = Process(target=func, args=(i,))
p.start()
print('这里是父亲进程%s' % (os.getpid()))
(2) 自定义类, 继承Process类
# 自定义类继承Process
class MyProcess(Process):
def __init__(self):
self.name = name
super(MyProcess, self).__init__(name=self.name) # 实现父类的__init__方法
def run(self):
print('这是以继承的方式开启子进程%s' % self.name)
if __name__ == '__main__':
name = 'alex'
p1 = MyProcess()
p1.start() # 是指解释器告诉操作系统, 去帮我开启一个进程, 属于就绪状态
# p1.run() # 告诉操作系统,现在马上执行这个子进程, 属于执行状态
3.如何开启多个不同的子进程
# 开启多个子进程
def func(i):
time.sleep(1)
print('这是第%s个子进程,进程id是%s' % (i, os.getpid()))
if __name__ == '__main__':
for i in range(10):
p = Process(target=func, args=(i,))
p.start()
print('父进程的ID是%s' % os.getpid())
4.进程的常用方法(start. join,terminate, is_alive)
from multiprocessing import Process
import time
def func():
for i in range(10):
time.sleep(0.1)
print('儿子在这里')
if __name__ == '__main__':
p = Process(target=func)
p.start()
p.join() # 当程序执行到这一句话时, 主进程开始阻塞. 等待子进程执行完
for i in range(10):
time.sleep(0.1)
print('爸爸在这里')
# 开启一个正常的子进程, 父进程会等待子进程结束后, 父进程也就是程序才结束
# p.join() 是主进程等待子进程执行完. 现象: 主进程执行到这句话时,主进程阻塞主,等待子进程执行
def func():
time.sleep(1)
print(123)
if __name__ == '__main__':
p = Process(target=func)
p.start()
p.terminate() # 杀死p进程, 让解释器告诉操作系统, 请杀死p进程
print('子进程是否活着?', p.is_alive())
print('父进程id%s'% os.getpid())
time.sleep(0.01)
print('子进程是否活着?', p.is_alive())
# 返回一个bool值, 如果返回True. 代表进程还活着, 如果返回False, 代表子进程死了
# p.is_alive() 判断p进程是否还活着
# p.terminate() 杀死p进程
- 如何把父进程和子进程之间的关系变为同步或者异步?
- 父进程执行join, 就会变成同步, 不执行join. 父进程和子进程的关系就是异步的关系
- join必须放在start() 后边
5.多个子进程
from multiprocessing import Process
import time
import random
def func(i):
print('我是%s' % i)
if __name__ == '__main__':
l = []
addr = ['上海的', '河南的', '北京的']
for i in addr:
p = Process(target=func, args=(i,))
p.start()
l.append(p)
[p.join() for p in l] # 列表推导式
time.sleep(1)
print('我选%s' % (random.choice(addr)))
6.进程的常用属性
- p.name = 给p进程一个名字
- p.pid 返回p进程的pid
- p.daemon = True 将p进程蛇者为守护进程,(True为守护进程, False 为普通进程)
- 守护进程的两个特点:
- 守护进程会随着父进程的结束而结束
- 守护进程不能再创建子进程
- 守护进程的两个特点:
四.队列,管道,回调函数
1.生产者消费者模型
- 主要是为了解耦
- 借助队列来实现生产者消费者模型
- 栈: 先进后出(First In Last Out 简称 FILO)
- 队列: 先进先出(First In First Out 简称FIFO)
import queue # 不能进行多进程之间的数据传输
(1) from multiprocessing import Queue 借助Queue来解决生产者消费者模型
队列是安全的
q = Queue(num) 实例化
num: 队列的最大长度
q.get() # 阻塞等待获取数据,如果有数据直接获取, 如果没有数据,阻塞等待
q.put() # 阻塞, 如果可以继续往队列中放数据,就直接放, 不能放就直接阻塞等待
q.get_nowait() # 不阻塞,如果有数据直接获取, 没有数据直接就报错
q.put_nowait() # 不阻塞,如果可以继续往队列中放数据, 就直接方放, 不能放就报错
(2) from multiprocessing import joinableQueue # 可连接队列
joinableQueue 是继承Queue,
并且joinableQueue多了两个方法
q.join() # 用于生产者 等待q.task_done的返回结果, 通过返回结果,生产者就能获取当前消费者消费了多少数据
q.task_done() # 用于消费者, 是指每消费队列中一个数据, 九个join返回一个标识
def consumer(q, name, color):
while 1:
info = q.get()
if info:
print(‘%s %s 拿走了%s \033[0m’ % (color, name, info))
else:
break
def producer(q, product):
for i in range(20):
q.put(product + ‘的娃娃%s’ % str(i))
if name == ‘main‘:
q = Queue(10)
p_con1 = Process(target=producer, args=(q, ‘贝贝’))
p_con2 = Process(target=producer, args=(q, ‘吉吉’))
p_con3 = Process(target=producer, args=(q, ‘果果’))
p_pro1 = Process(target=consumer, args=(q, ‘alex’, ‘\033[31m’))
p_pro2 = Process(target=consumer, args=(q, ‘wusir’, ‘\033[32m’))
l = [p_con1, p_con2, p_con3, p_pro1, p_pro2]
[p.start() for p in l]
# 父进程如何感知生产者子进程不再生产数据了?
p_con1.join()
p_con2.join()
p_con3.join()
q.put(None) # 几个消费者就要接受几个结束标识
q.put(None)
- joinableQueue新模块
rom multiprocessing import Process, JoinableQueue, Queue
def consumer(q, name, color):
while 1:
info = q.get()
print(‘%s %s 拿走了%s’ % (color, name, info))
q.task_done()
def producer(q, product):
for i in range(20):
q.put(product + ‘的娃娃%s号 \033[0m’ % str(i))
q.join()
if name == ‘main‘:
q = JoinableQueue(10)
p_con = Process(target=consumer, args=(q, ‘alex’, ‘\033[31m’))
p_pro = Process(target=producer, args=(q, ‘果果’))
p_con.daemon = True
p_con.start()
p_pro.start()
p_pro.join() # 主进程等待生产者进程结束
# 程序有3个进程,主进程和生产者进程和消费者进程。 当主进程执行到35行代码时,主进程会等待生产进程结束
# 而生产进程中(第26行)会等待消费者进程把所有数据消费完,生产者进程才结束。
# 现在的状态就是 主进程等待生产者进程结束,生产者进程等待消费者消费完所有数据
# 所以,把消费者设置为守护进程。 当主进程执行完,就代表生产进程已经结束,也就代表消费者进程已经把队列中数据消费完
# 此时,主进程一旦结束,守护进程也就是消费者进程也就跟着结束。 整个程序也就能正常结束了。
- Manger
from multiprocessing import Process, Manager
def func(num):
num[0] -= 1
print(‘子进程找中的num值是’, num)
if name == ‘main‘:
m = Manager()
num = m.list([1,2,3])
p = Process(target=func, args=(num,))
p.start()
p.join()
print(‘父进程中的num值是’, num)
- 管道使用
单进程管道的使用
from multiprocessing import Pipe
con1, con2 = Pipe()
con1.send(‘123’)
print(con2.recv())
con2.send(‘abd’)
print(con1.recv())
多进程管道的使用
from multiprocessing import Process, Pipe
def func(con):
con1, con2 = con
con1.close()
while 1:
try:
print(con2.recv())
except EOFError:
con2.close()
break
if name == ‘main‘:
con1, con2 = Pipe()
p = Process(target=func, args=((con1, con2),))
p.start()
con2.close() # 在父进程中, 使用con1 和 子进程通信, 所以不需要con2
for i in range(10): # 生产数据
con1.send(i) # 给子进程con2发送数据
con1.close() # 生产完数据, 关闭父进程这一端的管道
- 进程池和多进程效率对比
from multiprocessing import Pool, Process
import os
import time
def func(num):
num += 1
print(num)
if name == ‘main‘:
p = Pool(os.cpu_count() + 1)
start = time.time()
p.map(func, [i for i in range(100)])
p.close() # 值不允许向进程池中添加任务
p.join() # 等待进程池中所有进程执行完任务
print(‘进程池做任务的效率’, time.time() - start)
start = time.time()
p_l = []
for i in range(100):
p1 = Process(target=func, args=(i,))
p1.start()
p_l.append(p1)
[p1.join() for p1 in p_l]
print('多进程做任务的效率', time.time() - start)