python基础之Event对象、队列和多进程基础
Event对象
用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象
event对象默认为假(Flase),即遇到event对象在等待就阻塞线程的执行。
示例1:主线程和子线程间通信,代码模拟连接服务器
1 import threading
2 import time
3 event=threading.Event()
4
5 def foo():
6 print('wait server...')
7 event.wait() #括号里可以带数字执行,数字表示等待的秒数,不带数字表示一直阻塞状态
8 print('connect to server')
9
10 t=threading.Thread(target=foo,args=()) #子线程执行foo函数
11 t.start()
12 time.sleep(3)
13 print('start server successful')
14 time.sleep(3)
15 event.set() #默认为False,set一次表示True,所以子线程里的foo函数解除阻塞状态继续执行
示例2:子线程与子线程间通信
1 import threading
2 import time
3 event=threading.Event()
4
5 def foo():
6 print('wait server...')
7 event.wait() #括号里可以带数字执行,数字表示等待的秒数,不带数字表示一直阻塞状态
8 print('connect to server')
9 def start():
10 time.sleep(3)
11 print('start server successful')
12 time.sleep(3)
13 event.set() #默认为False,set一次表示True,所以子线程里的foo函数解除阻塞状态继续执行
14 t=threading.Thread(target=foo,args=()) #子线程执行foo函数
15 t.start()
16 t2=threading.Thread(target=start,args=()) #子线程执行start函数
17 t2.start()
示例3: 多线程阻塞
1 import threading
2 import time
3
4 event=threading.Event()
5 def foo():
6 while not event.is_set(): #返回event的状态值,同isSet
7 print("wait server...")
8 event.wait(2) #等待2秒,如果状态为False,打印一次提示继续等待
9 print("connect to server")
10
11 for i in range(5): #5个子线程同时等待
12 t=threading.Thread(target=foo,args=())
13 t.start()
14
15 print("start server successful")
16 time.sleep(10)
17 event.set() # 设置标志位为True,event.clear()是回复event的状态值为False
queue队列
队列是一只数据结构,数据存放方式类似于列表,但是取数据的方式不同于列表。
队列的数据有三种方式:
1、先进先出(FIFO),即哪个数据先存入,取数据的时候先取哪个数据,同生活中的排队买东西
2、先进后出(LIFO),同栈,即哪个数据最后存入的,取数据的时候先取,同生活中手枪的弹夹,子弹最后放入的先打出
3、优先级队列,即存入数据时候加入一个优先级,取数据的时候优先级最高的取出
代码实现
先进先出:put存入和get取出
1 import queue
2 import threading
3 import time
4 q=queue.Queue(5) #加数字限制队列的长度,最多能够存入5个数据,有取出才能继续存入
5 def put():
6 for i in range(100): #顺序存入数字0到99
7 q.put(i)
8 time.sleep(1) #延迟存入数字,当队列中没有数据的时候,get函数取数据的时候会阻塞,直到有数据存入后才从阻塞状态释放取出新数据
9 def get():
10 for i in range(100): #从第一个数字0开始取,直到99
11 print(q.get())
12
13 t1=threading.Thread(target=put,args=())
14 t1.start()
15 t2=threading.Thread(target=get,args=())
16 t2.start()
先进先出:join阻塞和task_done信号
1 import queue
2 import threading
3 import time
4 q=queue.Queue(5) #加数字限制长度
5 def put():
6 for i in range(100):
7 q.put(i)
8 q.join() #阻塞进程,直到所有任务完成,取多少次数据task_done多少次才行,否则最后的ok无法打印
9 print('ok')
10
11 def get():
12 for i in range(100):
13 print(q.get())
14 q.task_done() #必须每取走一个数据,发一个信号给join
15 # q.task_done() #放在这没用,因为join实际上是一个计数器,put了多少个数据,
16 #计数器就是多少,每task_done一次,计数器减1,直到为0才继续执行
17
18 t1=threading.Thread(target=put,args=())
19 t1.start()
20 t2=threading.Thread(target=get,args=())
21 t2.start()
先进后出:
1 import queue
2 import threading
3 import time
4
5 q=queue.LifoQueue()
6 def put():
7 for i in range(100):
8 q.put(i)
9 q.join()
10 print('ok')
11
12 def get():
13 for i in range(100):
14 print(q.get())
15 q.task_done()
16
17 t1=threading.Thread(target=put,args=())
18 t1.start()
19 t2=threading.Thread(target=get,args=())
20 t2.start()
按优先级:不管是数字、字母、列表、元组等(字典、集合没测),使用优先级存数据取数据,队列中的数据必须是同一类型,都是按照实际数据的ascii码表的顺序进行优先级匹配,汉字是按照unicode表(亲测)
列表
1 import queue
2 q=queue.PriorityQueue()
3 q.put([1,'aaa'])
4 q.put([1,'ace'])
5 q.put([4,333])
6 q.put([3,'afd'])
7 q.put([5,'4asdg'])
8 #1是级别最高的,
9 while not q.empty():#不为空时候执行
10 print(q.get())
元组
1 import queue
2 q=queue.PriorityQueue()
3 q.put((1,'aaa'))
4 q.put((1,'ace'))
5 q.put((4,333))
6 q.put((3,'afd'))
7 q.put((5,'4asdg'))
8 while not q.empty():#不为空时候执行
9 print(q.get())
汉字
1 import queue
2 q=queue.PriorityQueue()
3 q.put('我')
4 q.put('你')
5 q.put('他')
6 q.put('她')
7 q.put('ta')
8 while not q.empty():
9 print(q.get())
生产者与消费者模型
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这就像,在餐厅,厨师做好菜,不需要直接和客户交流,而是交给前台,而客户去饭菜也不需要不找厨师,直接去前台领取即可,这也是一个结耦的过程。
1 import time,random
2 import queue,threading
3
4 q = queue.Queue()
5
6 def Producer(name):
7 count = 0
8 while count <10:
9 print("making........")
10 time.sleep(random.randrange(3))
11 q.put(count)
12 print('Producer %s has produced %s baozi..' %(name, count))
13 count +=1
14 #q.task_done()
15 #q.join()
16 print("ok......")
17 def Consumer(name):
18 count = 0
19 while count <10:
20 time.sleep(random.randrange(4))
21 if not q.empty():
22 data = q.get()
23 #q.task_done()
24 #q.join()
25 print(data)
26 print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
27 else:
28 print("-----no baozi anymore----")
29 count +=1
30
31 p1 = threading.Thread(target=Producer, args=('A',))
32 c1 = threading.Thread(target=Consumer, args=('B',))
33 # c2 = threading.Thread(target=Consumer, args=('C',))
34 # c3 = threading.Thread(target=Consumer, args=('D',))
35 p1.start()
36 c1.start()
37 # c2.start()
38 # c3.start()
多进程基础
由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程
多进程优点:可以利用多核、实现并行运算
多进程缺点:切换开销太大、进程间通信困难
multiprocessing模块
multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的环境。
计算密集型串行计算:计算结果大概25秒左右
1 import time
2
3 def foo(n): #计算0到1亿的和
4 ret=0
5 for i in range(n):
6 ret+=i
7 print(ret)
8
9 def bar(n): #计算1到10万的乘积
10 ret=1
11 for i in range(1,n):
12 ret*=i
13 print(ret)
14 if __name__ == '__main__':
15 s=time.time()
16 foo(100000000)
17 bar(100000)
18 print(time.time()-s)
计算密集型多进程计算:计算结果13秒左右
1 import multiprocessing
2 import time
3
4 def foo(n):
5 ret=0
6 for i in range(n):
7 ret+=i
8 print(ret)
9
10 def bar(n):
11 ret=1
12 for i in range(1,n):
13 ret*=i
14 print(ret)
15
16 if __name__ == '__main__':
17 s=time.time()
18 p1 = multiprocessing.Process(target=foo,args=(100000000,)) #创建子进程,target: 要执行的方法;name: 进程名(可选);args/kwargs: 要传入方法的参数。
19 p1.start() #同样调用的是类的run方法
20 p2 = multiprocessing.Process(target=bar,args=(100000,) ) #创建子进程
21 p2.start()
22 p1.join()
23 p2.join()
24 print(time.time()-s)
继承类用法
1 from multiprocessing import Process
2 import time
3
4 class MyProcess(Process):
5 def __init__(self):
6 super(MyProcess, self).__init__()
7 # self.name = name
8
9 def run(self):
10 print ('hello', self.name,time.ctime())
11 time.sleep(1)
12
13 if __name__ == '__main__':
14 p_list=[]
15 for i in range(3):
16 p = MyProcess()
17 p.start()
18 p_list.append(p)
19
20 for p in p_list:
21 p.join()
22
23 print('end')
方法示例
1 from multiprocessing import Process
2 import os
3 import time
4
5 def info(name):
6 print("name:",name)
7 print('parent process:', os.getppid()) #获取父进程的id号
8 print('process id:', os.getpid()) #获取当前进程pid
9 print("------------------")
10 time.sleep(5)
11 if __name__ == '__main__':
12 info('main process') #第一次获取的是ide工具的进程和该代码文件的进程
13 p1 = Process(target=info, args=('alvin',)) #该代码文件的进程和p1的进程
14 p1.start()
15 p1.join()
对象实例的方法
实例方法:
is_alive():返回进程是否在运行。
join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
start():进程准备就绪,等待CPU调度
run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。
terminate():不管任务是否完成,立即停止工作进程
属性:
daemon:和线程的setDeamon功能一样
name:进程名字。
pid:进程号。
JoinableQueue同样通过multiprocessing使用。
创建队列的另外一个类:
JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
参数介绍:
from multiprocessing import Process,JoinableQueue
import time,random
def consumer(q):
while True:
time.sleep(random.randint(1,5))
res=q.get()
print('消费者拿到了 %s' %res)
q.task_done() def producer(seq,q):
for item in seq:
time.sleep(random.randrange(1,2))
q.put(item)
print('生产者做好了 %s' %item)
q.join() if __name__ == '__main__':
q=JoinableQueue()
seq=('包子%s' %i for i in range(10))
p=Process(target=consumer,args=(q,))
p.daemon=True #设置为守护进程,在主线程停止时p也停止,但是不用担心,producer内调用q.join保证了consumer已经处理完队列中的所有元素
p.start() producer(seq,q) print('主线程')
python基础之Event对象、队列和多进程基础的更多相关文章
- python Event对象、队列和多进程基础
Event对象 用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象 event对象默认为假(Flase),即遇到event对象在等待就阻塞线程 ...
- Python开发基础-Day31 Event对象、队列和多进程基础
Event对象 用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象 event对象默认为假(Flase),即遇到event对象在等待就阻塞线程 ...
- Python进阶(3)_进程与线程中的lock(线程中互斥锁、递归锁、信号量、Event对象、队列queue)
1.同步锁 (Lock) 当全局资源(counter)被抢占的情况,问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期.这种现象称为“线程不安全”.在开发过 ...
- Event对象、队列、multiprocessing模块
一.Event对象 线程的一个关键特性是每个线程都是独立运行且状态不可预测.如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就 会变得非常棘手.为了解决这些问题, ...
- 孤荷凌寒自学python第四十一天python的线程同步之Event对象
孤荷凌寒自学python第四十一天python的线程同步之Event对象 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 鉴于Lock锁与RLock锁均宣告没有完全完成同步文件操作的问题,于 ...
- python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)
python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...
- python学习之路-11 多线程、多进程、协程
python内置队列模块 queue queue的四种队列 q = queue.Queue() # 先进先出队列 q = queue.LifoQueue() # 后进先出队列 q = queue.Pr ...
- Python学习之路14☞多线程与多进程
一 进程与线程的概念 1.1 进程 进程定义: 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数 ...
- 线程、进程、daemon、GIL锁、线程锁、递归锁、信号量、计时器、事件、队列、多进程
# 本文代码基于Python3 什么是进程? 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是进程运行 ...
随机推荐
- 开发笔记:python与随机数(转)
这些天需要用到从一堆数中随机提取几个数,于是重新研究了下random模块. 下面介绍下random中常见的函数. 前提:需要导入random模块 >>>import random 1 ...
- STM32F10X FLASH and SRAM size
STM32F10X FLASH Size SRAM Size Device Type --------------------------------------------------------- ...
- Apache服务器和tomcat服务器有什么区别?
Apache与Tomcat都是Apache开源组织开发的用于处理HTTP服务的项目,两者都是免费的,都可以做为独立的 Web服务器运行.Apache是Web服务器而Tomcat是Java应用服务器. ...
- g++ 链接*.a静态库 方法
g++在链接*.a静态库时,直接作为object使用,不需要使用-l ,但是需要注意调整顺序,被依赖的文件放在后面. 如: g++ -g -o0 -Wno-deprecated -I$(INCL ...
- 【java】java工具类StringUtils,org.apache.commons.lang3.StringUtils
使用过程中,发现StringUtils工具类功能非常的多. 例如,判断元素是否为数字: StringUtils.isNumeric(string)
- nodejs 服务器 崩溃 2种解决办法
用node启动server后,发现服务器不稳定,经常crash.我是用ssh远程登录的,ssh远程通道中断,或者Ctrl+C,都会使nodejs server崩溃掉. 一,node server 崩溃 ...
- debian下安装mysql
apt-get install mysql-client mysql-server 中间会要你设置password,设置后后就自己主动启动mysql了 能够用ps -ef|grep mysql 这样能 ...
- Python学习 —— 阶段综合练习二
综合之前的类的学习,做以下实例练习:(建议先不要看代码,自己先试着写:代码仅供参考,有多种实现方法) 1. Triangle & Equilateral 1). 创建class Triang ...
- 高性能HTML
避免使用Iframe Iframe也叫内联frame,可以把一个HTML文档嵌入到另一个文档中.使用iframe的好处是被嵌入的文档可以完全独立于其父文档,凭借此特点我们通常可以使浏览器模拟多线程,需 ...
- qt study 元对象,属性和反射编程
所谓反射,就是指对象成员的自我检查,使用反射编程(reflective programming),就可以编写出通用的操作,可以对具有不同结构的类进行操作. QMetaObject 元对象模式,描述一个 ...