目录

1.锁:Lock

2.信号量:Semaphone

3.事件:Event

4.进程队列:Queue

5.生产者和消费者模型

6.JoinableQueue

锁:Lock

1.锁的基本概念

上锁和解锁是一对,只上锁不解锁会发生死锁现象(代码阻塞,不往下执行了)

互斥锁 : 互斥锁是进程之间的互相排斥,谁先抢到这个锁资源就先使用,后抢到后使用

2.锁的基本用法

# 创建一把锁
lock = Lock()
# 上锁
lock.acquire()
# 连续上锁不解锁是死锁
lock.acquire() # error print("厕所中...") # 解锁
lock.release()
print("执行程序 ... ")

对上面代码的一波分析:因为上锁后又解锁,所以最后一行的执行程序...可以打印出

但是如果连续上两把锁,解一把锁,则会产生死锁状态。无法打印后面的执行程序...

3.模拟12306抢票软件

# 读写数据库中的票数
def wr_info(sign, dic=None):
if sign == "r":
with open("ticket.txt", mode="r", encoding="utf-8") as fp:
dic = json.load(fp)
return dic elif sign == "w":
with open("ticket.txt", mode="w", encoding="utf-8") as fp:
json.dump(dic, fp) # 抢票方法
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 = ["Fly", "Hurt", "Mojo", "Snow", "1dao", "", "JieJ", "", "Gemini", "SK"]
for i in lst:
p = Process(target=run, args=(i, lock))
p.start()

运行结果如下图所示

代码分析:

创建进程的时候,仍然是异步并发,

在执行到上锁时,多个进程之间变成了同步程序.

先来的先上锁,先执行,后来的进程后上锁,后执行

信号量:Semaphone

信号量 Semaphore 本质上就是锁,只不过可以控制上锁的数量

1.Semaphore的基本用法

sem = Semaphore(4) # 锁的数量为4
sem.acquire()
sem.acquire()
sem.acquire()
sem.acquire()
# sem.acquire() # 上第五把锁出现死锁状态.
print("执行相应的操作")
sem.release()

2.模拟KTV房间唱歌

def ktv(person, sem):
sem.acquire()
print("%s进入了ktv,正在唱歌" % (person))
# 开始唱歌,唱一段时间
time.sleep(random.randrange(3, 7)) # 3 4 5 6
print("%s离开了ktv,唱完了" % (person))
sem.release() if __name__ == "__main__":
sem = Semaphore(4)
lst = ["Fly", "Hurt", "1dao", "Mojo", "Snow", "", "Giao", "SK", "", "Gemini"]
for i in lst:
p = Process(target=ktv, args=(i, sem))
p.start()

运行结果如下图所示

代码分析:

Semaphore 可以设置上锁的数量

同一时间最多允许几个进程上锁

创建进程的时候,是异步并发

执行任务的时候,遇到锁会变成同步程序.

事件:Event

1.Event中的基本方法

阻塞事件:

e = Event()生成事件对象e

e.wait()动态给程序加阻塞 , 程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False]

  如果是True 不加阻塞

  如果是False 加阻塞

控制这个属性的值:

set()方法 将这个属性的值改成True

clear()方法 将这个属性的值改成False

is_set()方法 判断当前的属性是否为True (默认上来是False)

2.Event的基本语法

1.小试牛刀

e = Event()
print(e.is_set()) # 默认是False状态
e.wait()
print("程序运行中 ... ")

运行结果如下图所示

2.is_set=True

e = Event()
e.set() # 将内部成员属性值由False -> True
print(e.is_set())
e.wait()
print("程序运行中 ... ") e.clear() # 将内部成员属性值由True => False
e.wait()
print("程序运行中2 ... ")

运行结果如下图所示

3.wait里加参数

e = Event()
# wait参数 可以写时间 wait(3) 代表最多等待3秒钟
e.wait(3)
print("程序运行中3 ... ")

3.模拟经典红绿灯效果

def traffic_light(e):
print("红灯亮")
while True:
if e.is_set():
# 绿灯状态,亮1秒钟
time.sleep(1)
print("红灯亮")
e.clear()
else:
# 红灯状态,亮1秒钟
time.sleep(1)
print("绿灯亮")
e.set() def car(e,i):
# not False => True => 目前是红灯,小车在等待
if not e.is_set():
print("car%s 在等待" % (i))
# 加阻塞
e.wait()
print("car%s 通行了" % (i)) # 不关红绿灯,一直跑
"""
if __name__ == "__main__":
e = Event()
# 创建交通灯对象
p1 = Process(target=traffic_light,args=(e,))
p1.start() # 创建车对象
for i in range(1,21):
time.sleep(random.randrange(0,2)) # 0 1
p2 = Process(target=car,args=(e,i))
p2.start()
""" # 当所有小车都跑完之后,把红绿灯收拾起来,省电
if __name__ == "__main__":
lst = []
e = Event()
# 创建交通灯对象
p1 = Process(target=traffic_light,args=(e,)) # 设置红绿灯为守护进程
p1.daemon = True
p1.start() # 创建车对象
for i in range(1,21):
time.sleep(random.randrange(0,2)) # 0 1
p2 = Process(target=car,args=(e,i))
p2.start()
lst.append(p2) # 让所有的小车都通行之后,在结束交通灯
for i in lst:
i.join() print("程序结束 ... ")

运行结果如下图所示

那么怎样才能做到,当20辆车已经通行之后,停止红绿灯的交替闪烁呢?

# 当所有小车都跑完之后,把红绿灯收拾起来,省电
if __name__ == "__main__":
lst = []
e = Event()
# 创建交通灯对象
p1 = Process(target=traffic_light, args=(e,)) # 设置红绿灯为守护进程
p1.daemon = True
p1.start() # 创建车对象
for i in range(1, 21):
time.sleep(random.randrange(0, 2)) # 0 1
p2 = Process(target=car, args=(e, i))
p2.start()
lst.append(p2) # 让所有的小车都通行之后,在结束交通灯
for i in lst:
i.join() print("程序结束 ... ")

运行结果如下图所示

代码分析:

1.设置p1交通信号灯为deamon守护进程,当主进程结束,守护进程-红绿灯进程也结束

2.i.join:当所有小车都通行之后,再结束交通信号灯进程

进程队列:Queue

什么是队列? 

队列特点: 先进先出,后进后出

1.put() 往队列里放值

q = Queue()
# 1.put 往队列中放值
q.put(100)
q.put(101)
q.put(102)

2.get() 从队列里取值

# 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 拿不到数据就报错

get_nowait  存在系统兼容性问题[windows]好用 [linux]不好用 不推荐

res = q.get_nowait()
print(res)

当然,我们可以使用try捕获到这个错误

try:
res = q.get_nowait()
print(res)
except queue.Empty:
pass

5.设置队列的长度

q2 = Queue(4)
q2.put(200)
q2.put(201)
q2.put(202)
q2.put(203)
# 如果超过了队列的指定长度,在继续存值会出现阻塞现象
# q2.put(204) # 超出长度会阻塞

6.put_nowait() 非阻塞版本的put,超出长度后,直接报错

q = Queue(3)
q.put(100)
q.put(101)
q.put(102)
q.put_nowait(204) # 超出队列长度,直接报错

同样,我们可以使用try捕获异常

try:
q2.put_nowait(205)
except queue.Full:
pass

7.进程之间的数据共享

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("主程序结束 ... ")

生产者和消费者模型

1.基本模型

def consumer(q,name):
while True:
food = q.get()
time.sleep(random.uniform(0.1,1))
print("%s 吃了一个%s" % (name,food)) # 生产者模型
def producer(q,name,food):
for i in range(5):
time.sleep(random.uniform(0.1,1))
# 打印生产的数据
print("%s 生产了 %s%s" % (name,food,i))
# 存储生产的数据
q.put(food + str(i)) if __name__ == "__main__":
q = Queue()
# 消费者
p1 = Process(target=consumer,args=(q,"宋云杰"))
# 生产者
p2 = Process(target=producer,args=(q,"马生平","黄瓜")) p1.start()
p2.start()

2.优化版

# 消费者模型
def consumer(q,name):
while True:
food = q.get()
if food is None:
break
time.sleep(random.uniform(0.1,1))
print("%s 吃了一个%s" % (name,food)) # 生产者模型
def producer(q,name,food):
for i in range(5):
time.sleep(random.uniform(0.1,1))
# 打印生产的数据
print("%s 生产了 %s%s" % (name,food,i))
# 存储生产的数据
q.put(food + str(i)) if __name__ == "__main__":
q = Queue()
# 消费者
p1 = Process(target=consumer,args=(q,"宋云杰"))
# 生产者
p2 = Process(target=producer,args=(q,"马生平","黄瓜")) p1.start()
p2.start() # 在生产者生产完所有数据之后,在队列的末尾添加一个None
p2.join()
# 添加None
q.put(None)

优化版和普通版有什么不同呢?

运行结果如下图所示

JoinableQueue

1.前戏

上面的生产者-消费者模型只是针对于一个生产者和一个消费者

那如果是多个生产者和多个消费者呢?

2.JoinableQueue基本语法

put 存储

get 获取

task_done

join

task_done 和 join 配合使用的

队列中 1 2 3 4 5

put 一次 内部的队列计数器加1

get 一次 通过task_done让队列计数器减1

join函数,会根据队列计数器来判断是阻塞还是放行

队列计数器 = 0 , 意味着放行

队列计数器 != 0 , 意味着阻塞

jq =JoinableQueue()
jq.put("a") # 向队列中存储一个a 并且队列计数器会加1
print(jq.get()) # 取出队列的a并打印
jq.task_done() # 通过task_done让队列计数器减1,此时队列计数器为0
jq.join() # 队列计数器为0,放行,打印下面的内容
print("finish")

3.用JoinableQueue优化生产者-消费者模型

def consumer(q, name):
while True:
food = q.get()
time.sleep(random.uniform(0.1, 1))
print("%s 吃了一个%s" % (name, food))
# 当队列计数器减到0的时,意味着进程队列中的数据消费完毕
q.task_done() # 生产者模型
def producer(q, name, food):
for i in range(5):
time.sleep(random.uniform(0.1, 1))
# 打印生产的数据
print("%s 生产了 %s%s" % (name, food, i))
# 存储生产的数据
q.put(food + str(i)) if __name__ == "__main__":
q = JoinableQueue()
# 消费者
p1 = Process(target=consumer, args=(q, "宋云杰"))
p3 = Process(target=consumer, args=(q, "李博伦"))
# 生产者
p2 = Process(target=producer, args=(q, "马生平", "黄瓜")) # 设置p1消费者为守护进程
p1.daemon = True
p3.daemon = True
p1.start()
p2.start()
p3.start() # 把所有生产者生产的数据存放到进程队列中
p2.join()
# 为了保证消费者能够消费完所有数据,加上队列.join
# 当队列计数器减到0的时,放行,不在阻塞,程序彻底结束.
q.join()
print("程序结束 ... ")

运行结果如下图所示

day33:进程II的更多相关文章

  1. day33——进程的创建方式、pid、空间隔离、join方法、其他属性、守护进程

    day33 进程创建的两种方式 在windows环境下,开启进程必须在______name______ == "______main______"下面 p.start(): 只是向 ...

  2. 8.15 day33 进程池与线程池_协程_IO模型(了解)

    进程池和线程池 开进程开线程都需要消耗资源,只不过两者比较的情况线程消耗的资源比较少 在计算机能够承受范围之内最大限度的利用计算机 什么是池? ​ 在保证计算机硬件安全的情况下最大限度地利用计算机 ​ ...

  3. python进程.线程和协程的总结

    I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...

  4. winfrom杀死进程及关闭进程

    ProcessStartInfo process = new ProcessStartInfo(); process.FileName = AppDomain.CurrentDomain.BaseDi ...

  5. C# 多线程学习系列一

    一.Windows线程的由来  关于操作系统的一些知识 (1).单个"工作线程"的问题 早期的Windows没有线程的概念,整个系统只有一个"工作线程",上面同 ...

  6. day33 线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁

    今日内容: 1.线程理论 2.锁: 牺牲了效率,保证了数据的安全(重点) 3.守护线程 4.GIL锁:(重点) 5.计算密集型和IO密集型 6.信号量,事件(了解) 7.补充. 子进程中不能input ...

  7. Cpython支持的进程与线程(Day33)

    一.multiprocessing模块介绍 python中的多线程无法利用CPU资源,在python中大部分情况使用多进程.python中提供了非常好的多进程包multiprocessing. mul ...

  8. day33 网络编程之UDP与进程了解

    UDP 什么是UDP协议 在上节课的练习中,使用TCP进行网络编程时,我们会遇到粘包问题,这是因为TCP是流式协议,而今天学习的UDP协议不是流式协议,其发送的数据是数据报格式的,在进行数据发送时该协 ...

  9. Linux服务器管理: 系统的进程管理终止进程kill命令

    在Linux中如何用kill终止进程: kill -l [root@localhost~]#kill -l   可以看到kill中有很多的 常用:  -1 是重启一个进程    -9 是强制杀死进程 ...

随机推荐

  1. python爬虫入门(3)----- scrapy

    scrapy 简介 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. 其最初是为了 页面抓取 (更确切来说, 网络 ...

  2. 五分钟快速搭建 Serverless 免费邮件服务

    1. 引言 本文将带你快速基于 Azure Function 和 SendGrid 构建一个免费的Serverless(无服务器)的邮件发送服务,让你感受下Serverless的强大之处. 该服务可以 ...

  3. springboot(三)SpringDataJPA完成CRUD

    参考博客—恒宇少年:https://www.jianshu.com/p/b6932740f3c0 纯洁的微笑:http://www.ityouknow.com/springboot/2016/08/2 ...

  4. smartSVN9.2.2 for mac 安装与破解

    原文链接:https://www.jianshu.com/p/bb87154e0459 近段时间使用svn进行项目管理,开始使用的是cornerstone,但是用过程中出现一个操作Bug,一.在xco ...

  5. PHP chop() 函数

    实例 移除字符串右侧的字符: <?php$str = "Hello World!";高佣联盟 www.cgewang.comecho $str . "<br& ...

  6. luogu P1712 [NOI2016]区间 贪心 尺取法 线段树 二分

    LINK:区间 没想到尺取法. 先说暴力 可以发现答案一定可以转换到端点处 所以在每个端点从小到大扫描线段就能得到答案 复杂度\(n\cdot m\) 再说我的做法 想到了二分 可以进行二分答案 从左 ...

  7. 承诺会计/预留款会计(commitment accounting/Encumbrance Accounting) in AX 2012

    作者:umfish  博文 http://blog.csdn.net/umfish/article/details/7751397 如果要使用Encmubrance Accounting, 需要先在G ...

  8. 类加载Class Loading

    JVM 何时.如何把 Class 文件加载到内存,形成可以直接使用的 Java 类型,并开始执行代码? ​ 类的生命周期 加载 - 连接(验证.准备.解析)- 初始化 - 使用 - 卸载. 注意,加载 ...

  9. 如何简单理解spring aop和事务

    用比喻的方法理解吧: 初学者的理解,仅仅为了个人好记 aop:由三部分组成:工具箱,工人,为工人分配工具 tx事务:由四部分组成:管理者,制度,工人,向工人通知管理制度  为什么这样理解呢?个人觉得好 ...

  10. 吴太银:华为消费者云服务Cassandra使用场景与最佳实践

    大家好,我是华为消费者云的吴太银. 我今天分享的主要是华为消费者云服务使用Cassandra的应用场景和最佳实践.我这个可能跟其他嘉宾分享的不太一样,因为前几个嘉宾讲的实际上对Cassandra原生的 ...