进程测试
python
复制代码
import os
import time
while True:
time.sleep(0.5)
print("hahaha")
print("self", os.getpid()) #获取自己的进程id
print("parent",os.getppid()) #parent 获取父进程的id
互斥锁
python
复制代码
# """
# 当多个进程共享一个数据时,可能会造成数据错乱
# 1.使用join 来让这些进程 串行 但是这将造成 无法并发 并且 进程执行任务的顺序就固定了
# 2.使用锁 将需要共享的数据加锁 其他进程在访问数据时 就必须等待当前进程使用完毕
#
# 锁的本质 就是一个bool类型的数据 在执行代码前 会先判断 这个值
# 注意 在使用锁时 必须保证锁是同一个
#
# 互斥锁
# 互相排斥的锁
#
# """
#
from multiprocessing import Process,Lock
import random
import time
def task1(lock):
lock.acquire() # 是一个阻塞的函数 会等到别的进程释放锁才能继续执行
lock.acquire()
print("1my name is:bgon")
time.sleep(random.randint(1,2))
print("1my age is:78")
time.sleep(random.randint(1, 2))
print("1my sex is:femal")
lock.release()
def task2(lock):
lock.acquire()
print("2my name is:blex")
time.sleep(random.randint(1, 2))
print("2my age is:68")
time.sleep(random.randint(1, 2))
print("2my sex is:femal")
lock.release()
def task3(lock):
pass
# 锁的实现原理 伪代码
# l = False
# def task3(lock):
# global l
# if l == False:
# l = True
# print("3my name is:常威")
# time.sleep(random.randint(1, 2))
# print("3my age is:68")
# time.sleep(random.randint(1, 2))
# print("3my sex is:femal")
# l = False
if __name__ == '__main__':
lock = Lock()
p1 = Process(target=task1,args=(lock,))
p1.start()
# p1.join()
p2 = Process(target=task2,args=(lock,))
p2.start()
# p2.join()
p3 = Process(target=task3,args=(lock,))
p3.start()
# p3.join()
#
# # 多个任务在共享一个数据时
# # 串行效率低 但是不会出问题
# # 并发效率高 但是数据可能错乱
#
#
#
# from multiprocessing import Lock,RLock,Process
#
# lock = Lock()
#
# lock.acquire()
# print("haha ")
# lock.acquire()
# print('test')
# lock.release()
# RLock 表示可重入锁 特点是 可以多次执行acquire
# Rlock 在执行多次acquire时 和普通Lock没有任何区别
# 如果在多进程中使用Rlock 并且一个进程a 执行了多次acquire
# 其他进程b要想获得这个锁 需要进程a 把锁解开 并且锁了几次就要解几次
# 普通锁如果多次执行acquire将会锁死
#
# lock = RLock()
# lock.acquire()
# lock.acquire()
# print("哈哈")
# lock.release()
# import time
# def task(i,lock):
# lock.acquire()
# lock.acquire()
# print(i)
# time.sleep(3)
# lock.release()
# lock.release()
# #第一个过来 睡一秒 第二个过来了 睡一秒 第一个打印1 第二个打印2
#
# if __name__ == '__main__':
# lock = RLock()
# p1 = Process(target=task,args=(1,lock))
# p1.start()
#
# p2 = Process(target=task, args=(2,lock))
# p2.start()
开启进程的两种方式
python
复制代码
from multiprocessing import Process
import os
#
def task(name):
print(name)
print("self",os.getpid())#66039
print("parent", os.getppid())#66038
print("task run")
# windows创建子进程时 子进程会将父进程的代码加载一遍 导致重复创建子进程
# 所以一定要将 创建子进程的代码放到main的下面
if __name__ == '__main__':
print("self", os.getpid()) #66038
print("parent", os.getppid()) #36520
p = Process(target=task, name="这是子进程!",kwargs={"name":"bgon"}) # 创建一个表示进程的对象 但并不是真正的创建进程
p.start() # 给操作系统发送通知 要求操作系统开启进程
# 创建进程的第二种方式 继承Process 覆盖run方法
# 在子进程启动以后会自动执行run方法
# 其优势是 可以自定义 进程的属性和行为 来完成一些额外任务 例如下载
# class MyProcess(Process):
#
# def __init__(self,url):
# self.url = url
# super().__init__()
#
# # 子类中的方法 只有run会被自动执行
# def run(self):
# print("下载文件...." , self.url)
# print(" run run run!")
#
# def task(self):
# pass
#
# def task():
# print(123)
# if __name__ == '__main__':
# p = MyProcess("www.baidu.com/xx.mp4")
# p.start()
进程间内存相互独立
python
复制代码
from multiprocessing import Process
import time
a = 1000000000000
def task():
global a
print(id(a))
a = 0
print("子进程的",a)
if __name__ == '__main__':
print(id(a))
p = Process(target=task)
p.start() # 给操作系统发送请求后 代码继续往下运行 至于子进程 什么时候创建 什么是执行 都跟当前进程没关系
time.sleep(1)
print("自己的",a)
# 子进程中的数据修改 不会影响父进程
互斥锁的使用场景_抢票
python
复制代码
import json
from multiprocessing import Process,Lock
import time
import random
"""
join和锁的区别
1.join中顺序是固定的 不公平
2.join是完全串行 而 锁可以使部分代码串行 其他代码还是并发
"""
# 查看剩余票数
def check_ticket(usr):
time.sleep(random.randint(1,3))
with open("ticket.json","r",encoding="utf-8") as f:
dic = json.loads(f.read())
print("%s查看 剩余票数:%s" % (usr,dic.get('count')))
def buy_ticket(usr):
with open("ticket.json","r",encoding="utf-8") as f:
dic = json.load(f)
if dic.get('count')> 0:
time.sleep(random.randint(1,3))
dic["count"] -= 1
with open("ticket.json", "w", encoding="utf-8") as f2:
json.dump(dic,f2)
print("%s 购票成功!" % usr)
else:
print('剩余票:',dic.get('count'))
print('Not Found of tiket!')
def task(usr,lock):
check_ticket(usr)
# time.sleep(1)
lock.acquire()
buy_ticket(usr)
lock.release()
if __name__ == '__main__':
lock = Lock()
for i in range(10):
p = Process(target=task,args=("用户%s" % i,lock))
p.start()
#p.join() # 只有第一个整个必须完毕 别人才能买 这是不公平的
父进程等待子进程结束
python
复制代码
import time
from multiprocessing import Process
# def task():
# print("上传文件....")
# time.sleep(3)
# print("上传结束...")
#
#
# # [进程1,进程2,进程3]
#
# if __name__ == '__main__':
# p = Process(target=task)
# p.start()
#
# p.join() # 本质上 是提高了子进程优先级 当CPU在切换时 会优先切子进程
#
# print("上传文件成功!")
def task(num):
print("我是%s号 进程" % num)
# time.sleep(1)
print("=========")
if __name__ == '__main__':
start_time = time.time()
ps = []
for i in range(1,4):
p = Process(target=task,args=(i,))
p.start()
print("----{}".format(i))
# ps.append(p)
for p in ps:
p.join()
print(time.time()-start_time)
print("over")
process 常用属性
python
复制代码
from multiprocessing import Process
import time
def task():
# time.sleep(3)
print("执行完毕!")
if __name__ == '__main__':
p = Process(target=task, name="alex")
p.start()
print(p.name)
#
# # time.sleep(1)
# print(p.is_alive())
# #
p.terminate()
# #
print(p.is_alive())
# # print(p.pid)
# p.terminate() # 终止这个进程
# print(p.pid)
# print(p.is_alive())
# p.daemon # 守护进程
死锁
python
复制代码
"""
死锁 指的是 锁 无法打开了 导致程序死卡
首先要明确 一把锁 时不会锁死的
正常开发时 一把锁足够使用 不要开多把锁
"""
from multiprocessing import Process,Lock
import time
def task1(l1,l2,i):
l1.acquire()
print("盘子被%s抢走了" % i)
time.sleep(1)
l2.acquire()
print("筷子被%s抢走了" % i)
print("吃饭..")
l1.release()
l2.release()
pass
def task2(l1,l2,i):
l2.acquire()
print("筷子被%s抢走了" % i)
l1.acquire()
print("盘子被%s抢走了" % i)
print("吃饭..")
l1.release()
l2.release()
if __name__ == '__main__':
l1 = Lock()
l2 = Lock()
Process(target=task1,args=(l1,l2,1)).start()
Process(target=task2,args=(l1,l2,2)).start()
IPC 进程间通讯
python
复制代码
"""
IPC 进程间通讯
由于进程之间内存是相互独立的 所以需要对应积极而方案 能够使得进程之间可以相互传递数据
1.使用共享文件,多个进程同时读写同一个文件
IO速度慢,传输数据大小不受限制
2.管道 是基于内存的,速度快,但是是单向的 用起来麻烦(了解)
3.申请共享内存空间,多个进程可以共享这个内存区域(重点)
速度快但是 数据量不能太大
"""
from multiprocessing import Manager,Process
#
# def task(m):
#
# print(m["num"])
#
# if __name__ == '__main__':
# # 开启了一个Manager
# with Manager() as m:
# m["num"] = 100 # 在这个空间中存储了一个num
#
# for i in range(20):
# p = Process(target=task,args=(m,))
# p.start()
#
#
from multiprocessing import Manager,Process,Lock
def work(d):
# with lock:
d['count']-=1
if __name__ == '__main__':
with Manager() as m:
dic=m.dict({'count':100}) #创建一个共享的字典
p_l=[]
for i in range(100):
p=Process(target=work,args=(dic,))
p_l.append(p)
p.start()
for p in p_l:
p.join()
print(dic)
僵尸进程
python
复制代码
import time
from multiprocessing import Process
def task1():
print("子进程 run")
if __name__ == '__main__':
for i in range(10):
p = Process(target=task1)
p.start()
time.sleep(100000)
队列
python
复制代码
"""
队列 不只用于进程间通讯
也是一种常见的数据容器
其特点是:先进先出
其优点是:可以保证数据不会错乱 即使在多进程下 因为其put和get默认都是阻塞的
对比堆栈刚好相反 :后进先出
#
"""
from multiprocessing import Queue
# q = Queue(1) # 创建一个队列 最多可以存一个数据
#
# q.put("张三")
# print(q.get())
#
# q.put("李四") # put默认会阻塞 当容器中已经装满了
#
# print(q.get())
# print(q.get()) # get默认会阻塞 当容器中已经没有数据了
#
# print("over")
q = Queue(1) # 创建一个队列 最多可以存一个数据
#
q.put("张三")
# q.put("李四",False) # 第二个参数 设置为False表示不会阻塞 无论容器是满了 都会强行塞 如果满了就抛异常
print(q.get())
print(q.get(timeout=3)) # timeout 仅用于阻塞时
# q.put("李四") # put默认会阻塞 当容器中已经装满了
#
# print(q.get())
# print(q.get()) # get默认会阻塞 当容器中已经没有数据了
#
# print("over")
生产者消费者模型
python
复制代码
"""
什么是生产者 消费者 模型
生产者 产生数据的一方
消费者 处理数据的一方
例如需要做一个爬虫
1.爬取数据
2.解析数据
爬去和解析都是耗时操作,如果正常按照顺序来编写代码,将造成解析需要等待爬去 爬去取也需要等待解析
这样效率是很低的
要提高效率 就是一个原则 让生产者和消费解开耦合 自己干自己的
如何实现:
1.将两个任务分别分配给不同进程
2.提供一个进程共享的数据容器
"""
import random
from multiprocessing import Process,Queue
import time
# 爬数据
def get_data(q):
for num in range(5):
print("正在爬取第%s个数据" % num)
time.sleep(random.randint(1,2))
print("第%s个数据 爬取完成" % num)
# 把数据装到队列中
q.put("第%s个数据" % num)
def parse_data(q):
for num in range(5):
# 取出数据
data = q.get()
print("正在解析%s" % data)
time.sleep(random.randint(1, 2))
print("%s 解析完成" % data)
if __name__ == '__main__':
# 共享数据容器
q = Queue(5)
#生产者进程
produce = Process(target=get_data,args=(q,))
produce.start()
#消费者进程
customer = Process(target=parse_data,args=(q,))
customer.start()
总结
python
复制代码
1. 并发编程
让你的程序可以同时处理多个任务
2.并发的基石是 多道技术
空间复用: 同一时间 内存存储了多个应用程序
不同应用程序之间的内存是相互独立的
时间复用: 当一个程序遇到了IO操作时 会切换到其他应用程序 ,以此来提高CPU的利用率
多道技术的缺点: 当应用程序都是计算任务时 切换反而降低效率 (但是必须得切 才能保证多任务并发)
3.并发 与 并行
并发 多个事件 同时发生, 也称之为伪并行
并行 多个事件 同时进行,
阻塞和非阻塞 指的是程序的状态
就绪 运行 阻塞
4.两种使用进程的方式
1.直接创建Process对象 指定target参数
2.继承Process 覆盖run方法
5.join函数
提高优先级 使 父进程等待子进程结束
6.孤儿进程与僵尸进程路径了解
孤儿进程 是指 父进程已经终止了 但是自己还在运行 是无害的
孤儿进程会自定过继给操作系统
僵尸进程 是指 子进程执行完成所有任务 已经终止了但是 还残留一些信息(进程id 进程名)
但是父进程 没有去处理这些残留信息 导致残留信息占用系统内存
僵尸进程时有害的
当出现大量的僵尸进程时 会占用系统资源 可以把它父进程杀掉 僵尸就成了孤儿 操作系统会负责回收数据