python进程和线程(四)
线程同步条件、信号量及队列
同步条件(event)
下面是官方文档对event的一些解释:
An event is a simple synchronization object;
the event represents an internal flag, and threads
can wait for the flag to be set, or set or clear the flag themselves.
event = threading.Event()
# a client thread can wait for the flag to be set
event.wait()
# a server thread can set or reset it
event.set()
event.clear()
If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event
也就是说:
event.isSet():返回event的状态值; event.wait():如果 event.isSet()==False将阻塞线程; event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度; event.clear():恢复event的状态值为False。
通过Event,我们可以实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红绿灯的规则。
import random
def light():
if not event.isSet():
event.set() #wait就不阻塞 #绿灯状态
count = 0
while True:
if count < 10: #绿灯10s
print('\033[42;1m--green light on---\033[0m')
elif count <13: #黄灯3s
print('\033[43;1m--yellow light on---\033[0m')
elif count <20: #红灯7s
if event.isSet():
event.clear()
print('\033[41;1m--red light on---\033[0m')
else: #重新开始第二轮红绿灯
count = 0
event.set() #打开绿灯
time.sleep(1)
count +=1
def car(n):
while 1:
time.sleep(random.randrange(10))
if event.isSet(): #绿灯
print("car [%s]正常行驶" % n)
else:
print("car [%s]在等红绿灯..." %n)
if __name__ == '__main__':
event = threading.Event()
Light = threading.Thread(target=light)
Light.start()
for i in range(4):
t = threading.Thread(target=car,args=(i,))
t.start()
运行之后就会看到4辆车在红绿灯时的状态了,非常简单,再看一个小例子就行了
import threading,time
class Mom(threading.Thread): def run(self):
print("妈妈:孩子们快回来吃饭")
# print(event.isSet())# False
event.set()
time.sleep(5)
print("妈妈:吃红烧肉")
print(event.isSet())
event.set() class Son(threading.Thread):
def run(self): event.wait()# 一旦event被设定,等同于pass print("一个孩子问:吃什么啊")
time.sleep(1)
event.clear()
event.wait()
print("一个孩子说:OhYeah!") if __name__=="__main__":
event=threading.Event() threads=[]
for i in range(5):
threads.append(Son())
threads.append(Mom())
for t in threads:
t.start()
for t in threads:
t.join() print("ending.....")
信号量(Semaphore)
之前讲的同步锁,是只允许一个线程去操作数据,而Semaphore就是同时允许一定数量的线程去操作数据。怎么说呢,比如100个人去洗脚城洗脚,只有五个技师,那一次只能同时五个人洗脚,后面的就只能排队等着了。原理也比较简单,就是BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。
import threading,time class myThread(threading.Thread):
def run(self): if semaphore.acquire():
print(self.name)
time.sleep(3)
semaphore.release() if __name__=="__main__":
semaphore=threading.Semaphore(5) thrs=[]
for i in range(100):
thrs.append(myThread())
for t in thrs:
t.start()
运行后,也可能出现我们同步锁里面说的并排打印的问题,这个就要看你个人需求了。
线程队列(queue)
之前我们在学校学过什么堆栈、队列的知识,在这里,没有堆栈这个概念,只有队列。
创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。 将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。 将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。
如果队列为空且block为False,队列将引发Empty异常。 Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize) 此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作
现在有一个需求,比如我有一个列表,要用多线程去移除列表最后一个元素,我们一般是这么写:
import threading,time li=[1,2,3,4] def pri():
while li:
a=li[-1]
print(a)
time.sleep(1)
li.remove(a)
# try:
# li.remove(a)
# except Exception as e:
# print('----',a,e) t1=threading.Thread(target=pri,args=())
t1.start()
t2=threading.Thread(target=pri,args=())
t2.start()
t1.join()
t2.join()
print(li)
但是运行过程中我们会发现报错,ValueError: list.remove(x): x not in list,同时操作这个元素的时候,发现这个元素已经被其他线程移除了,所以报错。这里想说明的是,列表在多线程中的操作是不安全的。
下面这个例子,是通过queue,来实现一个生产者和消费者模型,也就是说边做边吃
import time,random
import queue,threading
q = queue.Queue()
def Producer(name):
count = 0
while count <20:
time.sleep(random.randrange(5))
q.put(count)
print('Producer %s has produced %s baozi..' %(name, count))
count +=1
def Consumer(name):
count = 0
while count <20:
time.sleep(random.randrange(4))
if not q.empty():
data = q.get()
print(data)
print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
else:
print("-----no baozi anymore----")
count +=1
p1 = threading.Thread(target=Producer, args=('A',))
c1 = threading.Thread(target=Consumer, args=('B',))
c2 = threading.Thread(target=Consumer, args=('C',))
p1.start()
c1.start()
c2.start()
A是生产者,一直在做包子,做20个,B和C就是消费者,就是一直在吃包子,没有包子就喊。这里我们用的是q.empty()来判断队列中有没有包子,我们也可以通过q.task_done()和q.join()来完成这件事:
import time,random
import queue,threading q = queue.Queue() def Producer(name):
count = 0
while count <10:
print("making........")
time.sleep(3)
q.put(count)
print('Producer %s has produced %s baozi..' %(name, count))
count +=1
q.task_done()
# q.join()
print("ok......") def Consumer(name):
count = 0
while count <10:
time.sleep(random.randrange(4))
# if not q.empty():
print("waiting.....")
q.join()
data = q.get()
print("eating....")
time.sleep(4) # q.task_done()
print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
# else:
# print("-----no baozi anymore----")
count +=1 p1 = threading.Thread(target=Producer, args=('A君',))
c1 = threading.Thread(target=Consumer, args=('B君',))
c2 = threading.Thread(target=Consumer, args=('C君',))
c3 = threading.Thread(target=Consumer, args=('D君',)) p1.start()
c1.start()
c2.start()
c3.start()
就是说A君做好包子了,告诉队列,顾客这边在jion状态,包子没做好就一直等着,知道队列收到了包子做好的消息,也会告诉顾客能吃包子了,所以这里q.task_done()和q.join()是成对出现的,单个使用没什么意义,你也可以试试在厨师和顾客中调换位置使用。
线程的知识就讲到这里了,下面要说的是进程的内容,如果前面线程都掌握了,进程就相当简单,大同小异了。
python进程和线程(四)的更多相关文章
- python进程、线程、协程(转载)
python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资 ...
- Python进程、线程、协程详解
进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...
- python进阶:Python进程、线程、队列、生产者/消费者模式、协程
一.进程和线程的基本理解 1.进程 程序是由指令和数据组成的,编译为二进制格式后在硬盘存储,程序启动的过程是将二进制数据加载进内存,这个启动了的程序就称作进程(可简单理解为进行中的程序).例如打开一个 ...
- python 进程和线程(代码知识部分)
二.代码知识部分 一 multiprocessing模块介绍: python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情 ...
- python 进程与线程(理论部分)
一.理论部分 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的 ...
- Python 进程、线程、协程的介绍与使用
一.必备的理论基础 二.操作系统发展史 三.进程理论 四.线程理论 五.协程 一.必备的理论基础 操作系统理论: 操作系统是一个协调\管理\控制计算机硬件资源与应用软件资源的控制程序 操作系统的两大功 ...
- 这篇文章揭开python进程、线程、协程神秘的面纱
1.概念 [关注公众号"轻松学编程"了解更多. 回复"协程"获取本文源代码.] 从计算机硬件角度: 计算机的核心是CPU,承担了所有的计算任务. 一个CPU,在 ...
- python 进程和线程
python中的进程.线程(threading.multiprocessing.Queue.subprocess) Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就 ...
- Python进程、线程、协程
进程和线程的解释 进程(process)和线程(thread)是操作系统的基本概念,计算机的核心是CPU,它承担了所有的计算任务: 单个CPU一次只能运行一个任务,代表单个CPU总是运行一个进程,其他 ...
- Python进程和线程
引入进程和线程的概念及区别 1.线程的基本概念 概念 线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但 ...
随机推荐
- 如何深度复制一个javascript对象
前言 最近有人问我,如何将一个对象复制一份,因为他遇到了一个需求,需要将后端获取的数据,保存一份,原始数据会因为交互而发生变化,最终需要对比两份数据的异同. 他是一个刚入行的小朋友,他的实现方式就是新 ...
- 你不知道的JavaScript--Item15 prototype原型和原型链详解
用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了, ...
- java之集合Collection详解之3
package cn.itcast_03; public class Student { // 成员变量 private String name; private int age; // 构造方法 p ...
- Android 不规则封闭区域填充 手指秒变油漆桶
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/45954255: 本文出自:[张鸿洋的博客] 一.概述 在上一篇的叙述中,我们通 ...
- 吐槽一下--最近多次在腾讯以及万科的面试经历---Web前端与PHP后端开发
前端时间,由于职业发展等,想要换一份工作,于是投递了一些国内还算知名的公司,列如: 腾讯.万科之类的: (1)首先说一下这两家公司的反馈情况: 腾讯:投递到反馈,(初次人事打电话沟通)大约1周,三次不 ...
- orcl数据库命令行怎么导入dmp格式的文件
2018-05-23 1.创建空间 以system的身份登陆orcl 打开SQL Window界面,输入以下命令create tablespace SGXC(表空间的名字)datafile 'D:/S ...
- LOJ_6045_「雅礼集训 2017 Day8」价 _最小割
LOJ_6045_「雅礼集训 2017 Day8」价 _最小割 描述: 有$n$种减肥药,$n$种药材,每种减肥药有一些对应的药材和一个收益. 假设选择吃下$K$种减肥药,那么需要这$K$种减肥药包含 ...
- BZOJ_3173_[Tjoi2013]最长上升子序列_splay
BZOJ_3173_[Tjoi2013]最长上升子序列_splay Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数 ...
- BZOJ_1579_[Usaco2009 Feb]Revamping Trails 道路升级_分层图最短路
BZOJ_1579_[Usaco2009 Feb]Revamping Trails 道路升级_分层图最短路 Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M ...
- 斜率优化入门学习+总结 Apio2011特别行动队&Apio2014序列分割&HZOI2008玩具装箱&ZJOI2007仓库建设&小P的牧场&防御准备&Sdoi2016征途
斜率优化: 额...这是篇7个题的题解... 首先说说斜率优化是个啥,额... f[i]=min(f[j]+xxxx(i,j)) ; 1<=j<i (O(n^2)暴力)这样一个式子,首 ...