python多线程+生产者和消费者模型+queue使用
多线程简介
多线程:在一个进程内部,要同时干很多事情,就需要同时执行多个子任务,我们把进程内的这些子任务叫线程。
线程的内存空间是共享的,每个线程都共享同一个进程的资源
模块:
1、_thread模块 低级模块(在python3里基本已弃用)
2、threading模块 高级模块 对_thread模块进行了封装
threading模块使用
1.使用元组传递 threading.Thread(target=方法名,arg=(参数1,参数2...))
2.用字典传递 threading.Thread(target=方法名,kwargs={“参数名”:参数1,“参数名”:参数2,....})
3.混合使用元组和字典 threading.Thread(target=方法名,args=(参数1,参数2,...),kwargs={“参数名”:参数1,“参数名”:参数2,....})
4.查看线程数:
使用threading.enumerate()函数便可以看到当前线程的数量。
5.查看当前线程的名字:
使用threading.current_thread()可以看到当前线程的信息。
6.join([time]):等待至线程终止。这阻塞调用线程直至线程的join()方法被调用终止、正常退出或者抛出未处理的异常、或者是可选的超时发生。
7.isAlive():返回线程是否活动
8.getName(): 返回线程名
9.setNmae():设置线程名
10.后台线程(守护线程)
后台线程有一个特征:如果所有的前台线程都死亡了,那么后台线程也会自动死亡。
调用Thread对象的daemon属性可将指定线程设置为后台线程。在下面程序可以看到程序里的线程被指定为后台线程,当所有前台程序都死亡了后,后台线程随之死亡。当在整个虚拟机里只剩下后台线程时,程序就没有继续运行的必要了,所以程序也就退出了。
import threading
# 定义后台线程的线程执行体与普通线程没有任何区别
def action(max):
for i in range(max):
print(threading.current_thread().name + " " + str(i))
t = threading.Thread(target=action, args=(100,), name='后台线程')
# 将此线程设置成后台线程
# 也可在创建Thread对象时通过daemon参数将其设为后台线程
t.daemon = True
# 启动后台线程
t.start()
for i in range(10):
print(threading.current_thread().name + " " + str(i))
# -----程序执行到此处,前台线程(主线程)结束------
# 后台线程也应该随之结束
上面程序中的粗体字代码先将t线程设置成后台线程,然后启动该线程。本来该线程应该执行到i等于99时才会结束,但在运行程序时不难发现,该后台线程无法运行到99,因为当主线程也就是程序中唯一的前台线程运行结東后,程序会主动退出,所以后台线程也就被结東了。从上面的程序可以看出,主线程默认是前台线程,t线程默认也是前台线程。但并不是所有的线程默认都是前台线程,有些线程默认就是后台线程一一前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程
可见,创建后台线程有两种方式。
- 主动将线程的 daemon属性设置为True
- 后台线程启动的线程默认是后台线程。
以下看一个简单的多线程程序:
import threading
import time
def coding():
for x in range(3):
print('%s正在写代码' % x)
time.sleep(1)
def drawing():
for x in range(3):
print('%s正在画图' % x)
time.sleep(1)
def single_thread():
coding()
drawing()
def multi_thread():
t1 = threading.Thread(target=coding)
t2 = threading.Thread(target=drawing)
t1.start()
t2.start()
if __name__ == '__main__':
multi_thread()
继承自threading.Thread类:
为了让线程代码更好的封装。可以使用threading模块下的Thread类,继承自这个类,然后实现run方法,线程就会自动运行run方法中的代码。示例代码如下:
import threading
import time
class CodingThread(threading.Thread):
def run(self):
for x in range(3):
print('%s正在写代码' % threading.current_thread())
time.sleep(1)
class DrawingThread(threading.Thread):
def run(self):
for x in range(3):
print('%s正在画图' % threading.current_thread())
time.sleep(1)
def multi_thread():
t1 = CodingThread()
t2 = DrawingThread()
t1.start()
t2.start()
if __name__ == '__main__':
multi_thread()
start()和run()
start()
start()方法来启动线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码;通过调用Thread类的start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。run()
run()
run()方法当作普通方法的方式调用。程序还是要顺序执行,要等待run方法体执行完毕后,才可继续执行下面的代码; 程序中只有主线程——这一个线程, 其程序执行路径还是只有一条, 这样就没有达到写线程的目的。
记住:多线程就是分时利用CPU,宏观上让所有线程一起执行 ,也叫并发。start() 和 run()的区别说明
start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法。start()不能被重复调用。
run() : run()就和普通的成员方法一样,可以被重复调用。单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!
Lock版本生产者和消费者模型
生产者和消费者模式是多线程开发中经常见到的一种模式。生产者的线程专门用来生产一些数据,然后存放到一个中间的变量中。消费者再从这个中间的变量中取出数据进行消费。但是因为要使用中间变量,中间变量经常是一些全局变量,因此需要使用锁来保证数据完整性。以下是使用threading.Lock锁实现的“生产者与消费者模式”的一个例子:
import threading
import random
import time
gMoney = 1000
glo = threading.Lock()
gTotaltime = 10
gTime = 0
class Consumer(threading.Thread):
def run(self):
global gMoney
global gTime
while True:
money = random.randint(100,1000)
glo.acquire()
if gMoney>= money:
gMoney -= money
print("{}消费了{}元,当前剩余{}元".format(threading.current_thread(),money,gMoney))
else:
print("{}准备消费{}元,当前剩余{}元,不足,不能消费".format(threading.current_thread(),money,gMoney))
if gTime >= gTotaltime and money > gMoney:
glo.release()
break
glo.release()
time.sleep(0.7)
class Porducer(threading.Thread):
def run(self):
global gMoney
global gTime
while True:
Money = random.randint(100,700)
glo.acquire()
if gTime == gTotaltime:
glo.release()
break
gMoney += Money
print("{}生产了{}元钱,剩余{}元钱".format(threading.current_thread(),Money,gMoney))
gTime += 1
glo.release()
time.sleep(0.5)
def main():
for x in range(3):
t1 = Porducer(name="生产者")
t1.start()
for i in range(5):
t = Consumer(name="消费者")
t.start()
if __name__ == '__main__':
main()
queue线程安全队列
在线程中,访问一些全局变量,加锁是一个经常的过程。如果你是想把一些数据存储到某个队列中,那么Python内置了一个线程安全的模块叫做queue模块。Python中的queue模块中提供了同步的、线程安全的队列类,包括FIFO(先进先出)队列Queue,LIFO(后入先出)队列LifoQueue。这些队列都实现了锁原语(可以理解为原子操作,即要么不做,要么都做完),能够在多线程中直接使用。可以使用队列来实现线程间的同步。相关的函数如下:
- 初始化Queue(maxsize):创建一个先进先出的队列。
- qsize():返回队列的大小。
- empty():判断队列是否为空。
- full():判断队列是否满了。
- get():从队列中取最后一个数据。
- put(item,block=Ture,timeout=None):将一个数据放到队列中。如果队列已满,且block参数为Ture(阻塞),当前线程被阻塞,timeout指定阻塞时间,如果将timeout设置为None,则代表一直阻塞,直到有元素被放入队列中:如果队列已空,且block参数设置为False(不阻塞),则直接引发queue.Empty异常。
下面就可以用queue来进行线程通信
import queue
import time
import threading
def set_value(q):
index = 0
while True:
q.put(index)
index += 1
time.sleep(3)
def get_value(q):
index = 0
while True:
print(q.get())
time.sleep(0.5)
def main():
q = queue.Queue(4)
t1 = threading.Thread(target=set_value,args=[q])
t2 = threading.Thread(target=get_value,args=[q])
t1.start()
t2.start()
if __name__ == '__main__':
main()
python多线程+生产者和消费者模型+queue使用的更多相关文章
- Python之生产者&、消费者模型
多线程中的生产者和消费者模型: 生产者和消费者可以用多线程实现,它们通过Queue队列进行通信. import time,random import Queue,threading q = Queue ...
- python:生产者与消费者模型
1,生产者与消费者模型的矛盾在于数据供需的不平衡 import time import random from multiprocessing import Queue from multiproce ...
- 生产者、消费者模型---Queue类
Queue队列在几乎每种编程语言都会有,python的列表隐藏的一个特点就是一个后进先出(LIFO)队列.而本文所讨论的Queue是python标准库queue中的一个类.它的原理与列表相似,但是先进 ...
- python queue和生产者和消费者模型
queue队列 当必须安全地在多个线程之间交换信息时,队列在线程编程中特别有用. class queue.Queue(maxsize=0) #先入先出 class queue.LifoQueue(ma ...
- Python 之并发编程之进程下(事件(Event())、队列(Queue)、生产者与消费者模型、JoinableQueue)
八:事件(Event()) # 阻塞事件: e = Event() 生成事件对象e e.wait() 动态给程序加阻塞,程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值 ...
- Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁
Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...
- 人生苦短之我用Python篇(队列、生产者和消费者模型)
队列: queue.Queue(maxsize=0) #先入先出 queue.LifoQueue(maxsize=0) #last in fisrt out queue.PriorityQueue( ...
- python并发编程之守护进程、互斥锁以及生产者和消费者模型
一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...
- 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型
关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...
随机推荐
- Android_四大组件之Service
一.概述 Service是四大组件之一.它主要用于在后台执行耗时的逻辑,即使用户切换到其他应用甚至退出应用,它也能继续在后台运行. 下面主要介绍了service的两种形式启动和绑定 ,并通过简单例子说 ...
- Oracle 利用PLSQL一分钟将表结构(PROJ),从A库移植到B库,一分钟将A库中表数据移植到B库中!!!
导读(苦恼) 做多个项目的时候,可能会有这样的需求,需要把A项目中的某些功能移植到B项目上:移植途中,牵扯到顺便把表也要一块移植过去,若表字段较少,那还好,可能耗费10分钟就搞完了,万一碰上几十个字段 ...
- Emiya家今天的饭 NOIP2019 (CSP?) 类DP好题 luoguP5664
luogu题目传送门! 首先,硬求可行方案数并不现实,因为不好求(去年考场就这么挂的,虽然那时候比现在更蒟). 在硬搞可行方案数不行之后,对题目要求的目标进行转换: 可行方案数 = 总方案数 - 不合 ...
- Flutter,webview里面实现上传和下载的功能
前提:Flutter 与 webview(vue) 一起开发的项目 开始的时候并没有想到什么移动端的,所以上传就用input,下载就用iframe来实现,然而真机实测的时候,input那个方法IOS支 ...
- Beta冲刺 —— 5.29
这个作业属于哪个课程 软件工程 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.展示了每个人当天的成果. ...
- 又发现一款纯js开源电子表格Luckysheet
据官网介绍这个电子表格插件,是一款纯前端类似excel的在线表格,功能强大.配置简单.完全开源. 官网链接: Luckysheet官网 在线DEMO 特性包含: 表格设置,包括冻结行列.合并单元格.筛 ...
- Java实现 LeetCode 528 按权重随机选择(TreeMap)
528. 按权重随机选择 给定一个正整数数组 w ,其中 w[i] 代表位置 i 的权重,请写一个函数 pickIndex ,它可以随机地获取位置 i,选取位置 i 的概率与 w[i] 成正比. 说明 ...
- 阿里云专有网络配置以及交换机配置+ip、子网掩码、ip网段计算原理讲解
在阿里云上购买ECS或者其他服务,如redis.polardb时,需要配置专有网络,阿里的文档写的总体上还是比较抽象的,没有一定的网络基础,会一脸懵. 所以这里我来进行专有网络和交换机的配置,以及ip ...
- 简谈Java语言的继承
Java语言的继承 这里简谈Java语言的三大特性之二——继承. Java语言的三大特性是循序渐进的.是有顺序性的,应该按照封装-->继承-->多态这样的顺序依次学习 继承的定义 百度百科 ...
- nginx功能介绍和基本安装
一.简介 nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:nginx可以作为一个HTTP服务器进行网站的发布处理,另外ngi ...