Python开发基础-Day31 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:进程号。
时间: 2024-10-24 11:46:06

Python开发基础-Day31 Event对象、队列和多进程基础的相关文章

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() #括号里可

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() #括号里可

python开发concurent.furtrue模块:concurent.furtrue的多进程与多线程&amp;协程

一,concurent.furtrue进程池和线程池 1.1 concurent.furtrue 开启进程,多进程&线程,多线程 1 # concurrent.futures创建并行的任务 2 # 进程池 ProcessPoolExecutor,ThreadPoolExecutor 3 # 下面例子是Io密集型,所以时间上比叫多 4 from concurrent.futures import ProcessPoolExecutor 5 import os,time,random 6 def t

为什么越来越多的企业选择使用Python开发?

近来,Python作为一种功能强大且通用的编程语言而广受好评,它具有非常清晰的语法特点,适用于多种操作系统,目前在国际上非常流行,正在得到越来越多的应用.1.简介    Python,是一种面向对象.直译式的计算机程序语言,具有近二十年的发展历史.它包含了一组功能完备的标准库,能够轻松完成很多常见的任务.它的语法简单,与其他大多数程序设计语言使用大括号不同,它使用缩进来定义语句块.    Python支持命令式程序设计.面向对象程序设计.函数式编程.面向侧面的程序设计.范型编程多种编程范式. 2

Python多线程的threading Event

Python threading模块提供Event对象用于线程间通信.它提供了一组.拆除.等待用于线程间通信的其他方法. event它是沟通中最简单的一个过程之中,一个线程产生一个信号,号.Python 通过threading.Event()产生一个event对象.event对象维护一个内部标志(标志初始值为False),通过set()将其置为True.wait(timeout)则用于堵塞线程直至Flag被set(或者超时,可选的),isSet()用于查询标志位是否为True,Clear()则用

Day28:Event对象、队列、multiprocessing模块

一.Event对象 线程的一个关键特性是每个线程都是独立运行且状态不可预测.如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就 会变得非常棘手.为了解决这些问题,我们需要使用threading库中的Event对象. 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生.在初始情况下,Event对象中的信号标志被设置为假.如果有线程等待一个Event对象,而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真.一个线程如果将一个E

Python开发【第二十一篇】:Web框架之Django【基础】

Python开发[第二十一篇]:Web框架之Django[基础] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5237704.html Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. 基本配置 一.创建django程序 终端命令:django-a

windows上Python开发--3.Django的基础知识

最近两天下了班,没事学习了django的开发,今天做个总结.其实大家可以从百度,google搜到一些django的入门视频,初步了解一下django的框架.学习一些基础的概念和知识.本篇主要是对自己这两天做的做个总结. 1.创建第一个views.py 上一篇文章我们在windows上搭建好了django的开发环境并建立一个测试demo. 在settings.py的同级目录下新建views.py目录.并输入以下代码 from django.http import HttpResponse def

python开发面向对象基础:封装

一,封装 [封装] 隐藏对象的属性和实现细节,仅对外提供公共访问方式. [好处] 1. 将变化隔离: 2. 便于使用: 3. 提高复用性: 4. 提高安全性: [封装原则] 1. 将不需要对外提供的内容都隐藏起来: 2. 把属性都隐藏,提供公共方法对其访问. 私有变量和私有方法 在python中用双下划线开头的方式将属性隐藏起来(设置成私有的) 私有变量 #其实这仅仅这是一种变形操作 #类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A: __N=0 #类的数