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.线程的基本概念 概念 线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但 ...
随机推荐
- tkinter调取签名网而设计签名页面
# --*-- coding:utf-8 --*-- import tkinter as tk import re import requests from tkinter import messag ...
- jQuery学习之旅 Item1 选择器【一】
点击"名称"会跳转到此方法的jQuery官方说明文档. 1. 基础选择器 Basics 名称 说明 举例 #id 根据元素Id选择 $("divId") 选择I ...
- 解决Apache Web Server的几个错误
一.安装好Apache后服务里没有Apache服务 在命令行进入安装apache的bin目录下,输入命令 httpd.exe -k install -n Apache2.4 二.Apache web ...
- Linux下快速比较两个目录的不同
曾多次想要在Linux下比较目录a和目录b中文件列表的差别,然后对目录a比目录b中多出的文件.少掉的文件分别做处理.但是,在网上搜索了多次也都没找到能直接处理好的工具. 所以想了很多不少方法,自我感觉 ...
- Java与Kotlin, 哪个是开发安卓应用的首选语言?
Java是很多开发者创建安卓应用的首选语言.但它在 Android 界的领导地位正受到各种新语言的挑战,Kotlin就是其一.虽然Kotlin最近才开始受到热捧,但有为数不少的人相信 Kotlin 在 ...
- Java 学习笔记 (五) Java Compile\Build\Make的区别
以下内容引自: http://blog.51cto.com/lavasoft/436216 Compile.Make和Build的区别 原创leizhimin2010-11-30 11:30:20评论 ...
- ConcurrentHashMap简介
ConcurrentHashMap为了高并发而设计,相比于HashTable和HashMap有更多优势.HashTable是同步的,在多线程环境下,能保证程序执行的正确性,每次同步执行的时候都要锁住整 ...
- 在vs中编写代码常用的快捷键
作为一个程序员,能够熟悉使用各种快捷键,可以增加我们编写和调试代码的速度,下面我就对常使用的快捷键做一些总结,下面这些快捷键基本适用于所有版本的vs: 最给力: Ctrl+K+F 快速整理代码格式 ...
- 「CodeChef Dec13 REALSET」 Petya and Sequence 循环卷积
题目大意: 传送门 T组询问. 每组给一个数组,询问该数组是否循环移位线性无关,输出YES或NO. 题解: LCA冬令营有讲……然而当时…… 并不知道如何计算一个数组是否循环移位线性无关……网上也没有 ...
- 【线段树】Bzoj1798 [AHOI2009] 维护序列
Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2 ...