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:进程号。

python Event对象、队列和多进程基础的更多相关文章

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

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

  2. python基础之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 - 面对对象(基础) 一. 概述 二. 创建类和对象 三. 面向对象三大特征 封装 继承 多态 Python - 面对对象(基础) 一. 概述 面向过程:根据业务逻辑从上到下写垒代 ...

  7. 深入理解python(一)python语法总结:基础知识和对python中对象的理解

    用python也用了两年了,趁这次疫情想好好整理下. 大概想法是先对python一些知识点进行总结,之后就是根据python内核源码来对python的实现方式进行学习,不会阅读整个源码,,,但是应该会 ...

  8. python之路-----多线程与多进程

    一.进程和线程的概念 1.进程(最小的资源单位): 进程:就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成. 程序:我们编写的程序用来描述进程要完成哪些功能以 ...

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

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

随机推荐

  1. AXI Traffic Generator 生成axi-lite axi4 axis 的IP

    addr.coe memory_initialization_radix = ; memory_initialization_vector = ,,,,,,,,ffffffff; ctrl.coe m ...

  2. Redis的消息发布和订阅

    Redis的消息发布和订阅 Author:SimpleWu GitHub-redis 什么是消息发布和订阅? Redis 发布订阅(pub/sub)是一种进程间的消息通信模式: 发送者(pub)发送消 ...

  3. LeetCode(84): 柱状图中最大的矩形

    Hard! 题目描述: 给定 n 个非负整数,用来表示柱状图中各个柱子的高度.每个柱子彼此相邻,且宽度为 1 . 求在该柱状图中,能够勾勒出来的矩形的最大面积. 以上是柱状图的示例,其中每个柱子的宽度 ...

  4. 动态获取后台传过来的值作为select选项

    问题描述:点击左侧菜单项,进入对应的具体页面a.html,页面上方有个select框,点击框后,会浮现选择项. 解决思路:对左侧菜单项添加一个onclick事件,进入后台做具体的查询,将查询到的lis ...

  5. python网络爬虫笔记(九)

    4.1.1 urllib2 和urllib是两个不一样的模块 urllib2最简单的就是使用urllie2.urlopen函数使用如下 urllib2.urlopen(url[,data[,timeo ...

  6. poj2441状态压缩dp基础

    /* 给定n头牛,m个谷仓,每头牛只能在一些特定的谷仓,一个谷仓只能有一头牛 问可行的安排方式 dp[i][j]表示前i头牛组成状态j的方案数,状态0表示无牛,1表示有牛 使用滚动数组即可 枚举到第i ...

  7. python杂写

    一:用户交互 与用户交互主要使用input,这里需要说明三点: 1:input会等待用户输入 2:会将输入的内容赋值给变量 3:input出的变量都是字符串类型(str) 例子1:注意,因为input ...

  8. ecilpse运行Servlet程序是找不到路径的原因

    当工作空间路径有空格时,空格会被转成%20,将导致路径无法识别,于是就找不到路径了.

  9. Python数据分析几个比较常用的方法

    1,表头或是excel的索引如果是中文的话,输出会出错 ​​解决方法:python的版本问题!换成python3就自动解决了!当然也有其他的方法,这里就不再深究 2,如果有很多列,如何输出指定的列? ...

  10. Git 将本地库添加到远程仓库

    git remote add origin ssh://admin@127.0.0.1:29418/Prjs/prj1.git git push -u origin master