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
 

JoinableQueue同样通过multiprocessing使用。

创建队列的另外一个类:

JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

参数介绍:

    maxsize是队列中允许最大项数,省略则无大小限制。  
方法介绍:
    JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
    q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
    q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
 
示例1:
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对象、队列和多进程基础的更多相关文章

  1. python Event对象、队列和多进程基础

    Event对象 用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象 event对象默认为假(Flase),即遇到event对象在等待就阻塞线程 ...

  2. Python开发基础-Day31 Event对象、队列和多进程基础

    Event对象 用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象 event对象默认为假(Flase),即遇到event对象在等待就阻塞线程 ...

  3. Python进阶(3)_进程与线程中的lock(线程中互斥锁、递归锁、信号量、Event对象、队列queue)

    1.同步锁 (Lock) 当全局资源(counter)被抢占的情况,问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期.这种现象称为“线程不安全”.在开发过 ...

  4. Event对象、队列、multiprocessing模块

    一.Event对象 线程的一个关键特性是每个线程都是独立运行且状态不可预测.如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就 会变得非常棘手.为了解决这些问题, ...

  5. 孤荷凌寒自学python第四十一天python的线程同步之Event对象

     孤荷凌寒自学python第四十一天python的线程同步之Event对象 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 鉴于Lock锁与RLock锁均宣告没有完全完成同步文件操作的问题,于 ...

  6. python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)

    python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...

  7. python学习之路-11 多线程、多进程、协程

    python内置队列模块 queue queue的四种队列 q = queue.Queue() # 先进先出队列 q = queue.LifoQueue() # 后进先出队列 q = queue.Pr ...

  8. Python学习之路14☞多线程与多进程

    一 进程与线程的概念 1.1 进程 进程定义: 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数 ...

  9. 线程、进程、daemon、GIL锁、线程锁、递归锁、信号量、计时器、事件、队列、多进程

    # 本文代码基于Python3 什么是进程? 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是进程运行 ...

随机推荐

  1. 学习笔记:Tab Bar 控件使用详解

    注意这里是:Tab Bar 不是Tab Bar Controller. Tab bar是继承UIView,所以可以添加到ViewController里.是View就可以add到另一个View上去.Ta ...

  2. EntityFramework中几种操作小结

    目前项目中使用到的EntityFramework中几种操作小结,先标记下.没有详细介绍,后续有空的话再补充一些并完善一下. 列中加入RowVersion时间戳 public class Product ...

  3. Apache服务器和tomcat服务器有什么区别?

    Apache与Tomcat都是Apache开源组织开发的用于处理HTTP服务的项目,两者都是免费的,都可以做为独立的 Web服务器运行.Apache是Web服务器而Tomcat是Java应用服务器. ...

  4. js继承——从创建对象开始

    从创建对象开始 创建对象的简单方法就是:使用Object构造函数或者对象字面量.但这两个方法有个缺点:创建相同对象,要编写大量重复代码. 为了避免这个问题——>工厂模式:用函数封装以特定接口创建 ...

  5. React的第一个例子

    准备: 官网:https://facebook.github.io/react/downloads.html Github地址:https://github.com/facebook/react 首先 ...

  6. Git本地仓库与Github远程仓库关联

    如果你已经在本地创建了一个Git仓库,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,那就需要用到SSH Key,github拿到了你的公钥就会知道内容是你推送的. SSH Key ...

  7. weblogic打补丁,bsu方法

    刚装了10.3.6版本的weblogic,想把版本补丁到10.3.6.0.12 我用的系统是windows 8.1 ,呵呵 查看版本 执行java weblogic.version WebLogic ...

  8. jacob使用入门及问题解析

    转自:http://blog.csdn.net/hemingwang0902/article/details/4377994 本博客 jacob 列文章导读Java操作Microsoft Word之j ...

  9. [翻译] DFCircleActivityIndicator DF圆形活动状态指示器

    DFCircleActivityIndicator Native, customizable and animated circular view to show when long activity ...

  10. 深度学习Deep learning

    In the last chapter we learned that deep neural networks are often much harder to train than shallow ...