进程
1. 进程调度
1. 先来先服务
2. 短作业优先
3. 时间片轮转
4. 多级反馈队列
2. 僵尸进程 孤儿进程
1. 僵尸进程: 进程结束了,资源还没来得及回收
2. 孤儿进程: 主进程退出,子进程还没有结束,他就会被专门的进程接管
3. 进程对象及其他方法
# 1. windows : tasklist | findstr PID
# 2. mac linux : ps aux | grep PID
# 3. 进程对象: t = Process(target=task)
# 进程内部: current_process()
# 4. t.pid 或者 current_process().pid => 获取进程 id 号
# 5. os.getpid() 获取进程 id 号
# 6. os.getppid() 获取父进程 id 号
# 7. t.is_alive()或current_process().is_alive() 查看进程是否存活
# 8. t.terminate() 关闭进程,在主进程关闭
# 案例
import os
import time
from multiprocessing import Process
from multiprocessing import current_process
# 每个进程都会有自己的 id号: pid
def task():
print('子进程')
# 当前进程的 id 号
print(current_process().pid)
print(os.getpid()) # 跟上面打印出来是一模一样的
# 取出该进程的父 id 号
print(os.getppid())
# current_process() 当前进程对象
print(current_process().is_alive())
time.sleep(2)
print('子进程结束')
if __name__ == "__main__":
t = Process(target=task)
t.start()
t1 = Process(target=task)
t1.start()
t.is_alive()
print('主进程打印结果',t.is_alive())
print(t.pid)
time.sleep(0.5)
t.terminate() # 把 t 进程关闭
print('主进程打印结果',t.is_alive)
4. 守护进程
import os
import time
from multiprocessing import Process
from multiprocessing import current_process
def task():
# print(os.getpid())
print('子进程')
time.sleep(100)
print('子进程结束')
if __name__ == "__main__":
t = Process(target=task)
# 守护进程: 主进程一旦结束,子进程也随之结束
t.daemon = True # 一定要加在启动之前
t.start()
time.sleep(1)
print('主进程结束')
print('os.getppid()')
time.sleep(100)
5. 互斥锁
# 同时只有一个人能拿到,必须释放,其他人才能再次获取到
import json
import time
import random
from multiprocessing import Process
from multiprocessing import Lock
def search():
# 查看票数
# 打开文件 读出 ticket_count
with open('ticket','r',encoding='utf-8') as f:
dic = json.load(f)
print('余票还有: ',dic.get('ticket_count'))
def buy():
with open('ticket','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','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()
# ### 锁 lock
from multiprocessing import Process,Lock
# (1) lock基本用法
"""
上锁和解锁是一对,只上锁不解锁会发生死锁现象(代码阻塞,不往下执行了)
互斥锁 : 互斥锁是进程之间的互相排斥,谁先抢到这个锁资源就先使用,后抢到后使用
"""
"""
# 创建一把锁
lock = Lock()
# 上锁
lock.acquire()
# 连续上锁不解锁是死锁
# lock.acquire() error
print("厕所中...")
# 解锁
lock.release()
print("执行程序 ... ")
"""
# (2) 模拟12306抢票软件
import json,time
# 读写数据库中的票数
def wr_info(sign,dic=None):
if sign == "r":
with open("ticket",mode="r",encoding="utf-8") as fp:
dic = json.load(fp)
return dic
elif sign == "w":
with open("ticket",mode="w",encoding="utf-8") as fp:
json.dump(dic,fp)
# res = wr_info("r")
# print(res)
# dic = {"count":0}
# wr_info("w",dic)
# 抢票方法
def get_ticket(person):
# 获取数据库中实际的票数
dic = wr_info("r")
print(dic)
# 模拟一下网络延迟
time.sleep(0.5)
# 判断票数
if dic["count"] > 0 :
print("%s抢到票了" % (person))
dic["count"] -= 1
wr_info("w",dic)
else:
print("%s没有抢到这张票" % (person))
def run(person,lock):
# 查看剩余票数
dic = wr_info("r")
print("%s 查询票数: %s" % (person , dic["count"]) )
# 上锁
lock.acquire()
# 开始抢票
get_ticket(person)
lock.release()
if __name__ == "__main__":
lock = Lock()
lst = ["李志辉","宋云杰","高云峰","戈隆","孙致和","李虎玲","袁伟倬","刘鑫炜","马生平","刘鑫"]
for i in lst:
p = Process(target=run,args=(i,lock))
p.start()
"""
创建进程的时候,仍然是异步并发,
在执行到上锁时,多个进程之间变成了同步程序.
先来的先上锁,先执行,后来的进程后上锁,后执行
"""
6. 面向对象高级
# 面向对象高级: 魔法方法 (__开头的) , __enter__ 和 __exit__,
# with 上下文管理器
# 自己写一个类,实现类似于打开文件 with open 的功能
'''
with MyClass('文件名','方式','编码') as f:
f.read()
顶格写代码,f就关闭了
'''
class MyClass():
def __init__(self,file_name,mode,encoding):
self.file_name = file_name
self.mode = mode
self.encoding = encoding
def __enter__(self):
print('只要有with,就会执行我')
self.file = open(self.file_name,self.mode,encoding=self.encoding)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
# 只要顶格写代码,就会执行我
print('只要顶格写代码,就会执行我')
self.file.close()
with MyClass('ticket','r','utf-8') as f:
print(f.read())
print('xxss')
print('safdas')
a = MyClass('ticket','r','utf-8')
7. 队列介绍
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(timeout=0.1)) # 等0.1s还没有值,就结束
print(q.get_nowait()) # 不等,有就是有,没有就没有
print(q.empty()) # 看一下队列是不是空的
print(q.full()) # 看一下队列是不是满的
# 总结
'''
q = Queue(队列大小)
# 放值
q.put(abcd)
q.put_nowait(abcd) # 队列满了,放不进去就不放,报错
# 取值
q.get() # 从队列头部取出一个值
q.get_nowait() # 从队列头部取值,没有就报错
# 队列是否为空,是否满
print(q.empty()) # 看一下队列是不是空的
print(q.full()) # 看一下队列是不是满的
'''
from multiprocessing import Process,Queue
import queue
"""队列特点: 先进先出,后进后出"""
q = Queue()
# 1.put 往队列中放值
q.put(100)
q.put(101)
q.put(102)
# 2.get 从队列中取值
res = q.get()
print(res)
res = q.get()
print(res)
# res = q.get()
# print(res)
# 3.队列中如果已经没有数据了,在调用get会发生阻塞.
res = q.get()
print(res)
# 4.get_nowait 存在系统兼容性问题[windows]好用 [linux]不好用 不推荐
res = q.get_nowait()
print(res)
try:
res = q.get_nowait()
print(res)
except queue.Empty:
pass
# 5.设置队列的长度
"""设置队列长度最多存放4个元素"""
print("<======>")
q2 = Queue(4)
q2.put(200)
q2.put(201)
q2.put(202)
# q2.put(203)
# 如果超过了队列的指定长度,在继续存值会出现阻塞现象
# q2.put(204)
# 6.put_nowait() 非阻塞版本的put,超出长度后,直接报错
q2.put_nowait(204)
try:
q2.put_nowait(205)
except queue.Full:
pass
# ### 2.进程之间的数据共享
def func(q3):
# 2.子进程获取数据
res = q3.get()
print(res)
# 3.子进程存数据
q3.put("马生平")
if __name__ == "__main__":
q3 = Queue()
p = Process(target=func,args=(q3,))
p.start()
# 1.主进程添加数据
q3.put("王凡")
# 为了等待子进程把数据放到队列中,需要加join
p.join()
# 4.主进程获取数据
res = q3.get()
print(res)
print("主程序结束 ... ")
8. 进程间通信 IPC
IPC : Inter-Process Communication
import os
import time
from multiprocessing import Process
from multiprocessing import current_process
from multiprocessing import Queue
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())
if __name__ == '__main__':
q = Queue(5)
t1 = Process(target=task1,args=(q,))
t1.start()
t2 = Process(target=task2,args=(q,))
t2.start()
print(q.get())
9. Manager 进程间共享数据
# Manager ( list 列表 , dict 字典) 进程之间的共享数据(列表或者字典等)
from multiprocessing import Process,Manager,Lock
def work(data,lock):
# 1.正常写法
# 上锁
lock.acquire()
# 修改数据
data["count"] -= 1
# 解锁
lock.release()
# 2.使用with语法可以简化上锁和解锁两步操作
with lock:
data[0] += 1
if __name__ == "__main__":
lst = []
lock = Lock()
m = Manager()
data = m.dict( {"count":20000} )
data = m.list( [1,2,3] )
for i in range(50):
p = Process(target=work,args=(data,lock))
p.start()
lst.append(p)
# 确保所有进程执行完毕之后,在向下执行,打印数据,否则报错.
for i in lst:
i.join()
print(data)