多道技术
多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一个资源(如cpu)的有序调度问题,解决方式即多路复用,多路复用分为时间上的复用和空间上的复用
空间上的复用:将内存分为几部分,每一个部分放一个程序,这样,同一时间内存中就由了多道程序
时间上的复用:当一个程序在等待io时,另一个程序可以使用CPU,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%,类似于小学所学的统筹方法.
操作系统采用了多道技术后,可以控制进程的切换,或者说进程之间去争抢cpu的执行权限,这种切换不仅会在一个进程遇到io时进行,一个进程占用cpu时间过长也会被切换,或者说被操作系统夺走cpu的执行权限.
进程调度:
1.先来先服务 FCFS
2.短作业优先
3.时间片轮转
4.多级反馈队列
进程的三种状态:就绪,阻塞,运行
同步异步,阻塞非阻塞
同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而程序继续处于激活状态.而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行代码,函数返回的时候通过状态,通知,事件等方式通知进程任务完成
阻塞非阻塞是针对进程或线程,阻塞是当请求不能满足的时候就将进程挂起(如遇到io),而非阻塞则不会阻塞当前进程.
创建进程的两种方式:
# 第一种:先定义函数,后调用multiprocessing模块创建子进程
# from multiprocessing import Process
# import time
#
#
# def task(n):
# print('我是子进程')
# time.sleep(n)
# print('子进程结束')
#
#
# if __name__ == '__main__':
# # args=(), kwargs={}
# # t=Process(task,args=(1,))
# t = Process(target=task, kwargs={'n': 1})
# t.start() # 通知操作系统,开启进程,执行task函数
# print('主')
# 第二种:调用multiprocessing模块,创建类,继承Process,注意:__init__方法中,先继承父类的__init__方法,这样实例化的时候结果就是进程,后面调用的时候不是调用run,还是start()
# from multiprocessing import Process
# import time
#
# class Task(Process):
# def __init__(self, n):
# super().__init__()
# self.n = n
#
# def run(self):
# print('我是子进程')
# time.sleep(self.n)
# print('子进程结束')
#
#
# if __name__ == '__main__':
# t = Task(1)
# # t.run(1) # 不是调用t.run(),而是调用t.start()
# t.start()
# print('主')
join方法:等待子进程执行完成
PS:t.join() 可控制子进程执行完毕后才继续执行下面代码
进程间数据相互隔离:
建立的子进程中的数据变更,与主进程中的数据无关,两者隔离没有关系
进程对象及其他方法
1.windows: tasklist |findstr 进程的id号
2.mac,linux: ps aux | grep 进程id号
3.进程对象: t = Process(target = task,) 或者在进程内部 current_process()
4.t.pid或者 current_process().pid 获取进程id号
5.os.getpid()同上,获取进程的id号
6.os.getppid()获取父进程的id号,子进程中获取父进程id,等于父进程的id号
7.t.is_alive()或者current_process().is_alive() 查看进程是否存活
8.t.terminate()关闭进程,在主进程关闭 PS:异步操作,不是立即关闭的,需要时间
僵尸进程与孤儿进程
僵尸进程:进程结束了,但是资源还没来得及回收
孤儿进程:主进程挂了,子进程还没结束,他就会被专门的进程接管
守护进程
定义:一旦主进程结束,子进程也结束
语法:t.daemon = True 一定要加在启动start之前
# from multiprocessing import Process,current_process
# import time
# import os
#
# def task():
# print(os.getpid())
# print('子进程')
# time.sleep(200)
# print('子进程结束')
#
#
# if __name__ == '__main__':
# t = Process(target=task, )
# # 守护进程:主进程一旦结束,子进程也结束
# t.daemon=True # 一定要加在启动之前
# t.start()
#
#
# time.sleep(1)
# print('主进程结束')
互斥锁:同时只有一个人能拿到,必须释放,其他人才能再次获取到,并行改串行
# from multiprocessing import Process, Lock
# import json
# import time
# import random
#
#
# def search():
# # 查票的函数
# # 打开文件,读出ticket_count
# with open('ticket.json', 'r', encoding='utf-8') as f:
# dic = json.load(f)
# print('余票还有:', dic.get('ticket_count'))
#
#
# def buy():
# with open('ticket.json', 'r', encoding='utf-8') as f:
# dic = json.load(f)
#
# time.sleep(random.randint(1, 3)) # 模拟一下网络延迟
# if dic.get('ticket_count') > 0:
# # 能够买票
# dic['ticket_count'] -= 1
# # 保存到文件中去
# with open('ticket.json', 'w', encoding='utf-8') as f:
# json.dump(dic, f)
# print('买票成功')
# else:
# # 买票失败
# print('买票失败')
#
#
# # 写一个函数,先查票,再买票
#
# def task(mutex):
# search()
# # 买票过程要加锁
# # 买前加锁
# # mutex.acquire()
# # buy() # 10个进程变成了串行执行
# # # 买后释放锁
# # mutex.release()
# with mutex:
# buy()
#
#
# if __name__ == '__main__':
# # 锁的创建,在哪?主进程创建锁
# mutex = Lock() # 创建一把锁
# # 模拟十个人买票(开10个进程)
# for i in range(10):
# t = Process(target=task, args=(mutex,))
# t.start()
PS:分析:查票和买票的函数比较简单,创建函数task,将查票和买票放到一起,其中需要加上互斥锁的只有买票环节,主进程先创建一把锁:mutex = Lock(),在task函数中,买前先加锁,mutex.acquire(),买完后释放锁 mutex.release(),可用上下文管理 with 来替代,with mutex
创建10个子进程,用for i in range(10)来就可以
队列
# from multiprocessing import Queue
#
#
# # 实例化得到要给对象
#
# q=Queue(5) # 默认很大,可以放很多,写了个5,只能放5个
#
# # 往管道中放值
# q.put(1)
#
# q.put('lqz')
# q.put(18)
# q.put(19)
# q.put(20)
# # q.put(21)
# q.put_nowait(100)
#
# # 从管道中取值
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# # print(q.get(timeout=0.1)) # 等0.1s还没有值,就结束
# print(q.get_nowait()) # 不等了,有就是有,没有就没有
# print(q.queue)
#
#
#
# print(q.empty()) # 看一下队列是不是空的
# print(q.full()) # 看一下队列是不是满的
PS 注意点:q=Queue(5) 括号内为队列值的个数,小于等于0不限制,若往里塞的个数q.put()大于这个值,则阻塞,q.get()为删除队列的值并返回,若删除不到,则报错,put_nowait,get_nowait 都是不等,直接操作,不行就报错,get(timeout = 0.1)等0.1秒,没有值就结束
# 总结:
'''
q=Queue(队列大小)
# 放值
q.put(asdf)
q.put_nowait(asdf) # 队列满了,放不进去就不放了,报错
# 取值
q.get() # 从队列头部取出一个值
q.get_nowait() # 从队列头部取值,没有就抛错
# 队列是否为空,是否满
print(q.empty()) # 看一下队列是不是空的
print(q.full()) # 看一下队列是不是满的
'''
IPC机制:进程间通信:Inter-Process Communication
from multiprocessing import Process, current_process, Queue
# import time
# import os
#
#
# def task1(q):
# print('我是task1进程,我的id号是:%s'%os.getpid())
# q.put('lqz is handsome')
#
#
# def task2(q):
#
# # res=q.get()
# # print('我是task2进程,我的id号是:%s'%os.getpid(),res)
# print('我是task2进程,我的id号是:%s'%os.getpid())
# q.put('第二次通信')
# # print(q.get())
#
# if __name__ == '__main__':
# q = Queue(5)
#
# t1 = Process(target=task1, args=(q,))
# t1.start()
# t1.join()
# t2 = Process(target=task2, args=(q,))
# t2.start()
#
# print(q.get())
PS:IPC机制,实现了进程之间的数据交换,但是子进程是异步的,执行速度有差异,数据存入管道中的速度也有差异,故取出的数据随机
并发编程总体课程1
最新推荐文章于 2023-12-31 17:12:30 发布