多线程简介

多线程:在一个进程内部,要同时干很多事情,就需要同时执行多个子任务,我们把进程内的这些子任务叫线程。

线程的内存空间是共享的,每个线程都共享同一个进程的资源

模块:

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属性可将指定线程设置为后台线程。在下面程序可以看到程序里的线程被指定为后台线程,当所有前台程序都死亡了后,后台线程随之死亡。当在整个虚拟机里只剩下后台线程时,程序就没有继续运行的必要了,所以程序也就退出了。

  1. import threading
  2. # 定义后台线程的线程执行体与普通线程没有任何区别
  3. def action(max):
  4. for i in range(max):
  5. print(threading.current_thread().name + " " + str(i))
  6. t = threading.Thread(target=action, args=(100,), name='后台线程')
  7. # 将此线程设置成后台线程
  8. # 也可在创建Thread对象时通过daemon参数将其设为后台线程
  9. t.daemon = True
  10. # 启动后台线程
  11. t.start()
  12. for i in range(10):
  13. print(threading.current_thread().name + " " + str(i))
  14. # -----程序执行到此处,前台线程(主线程)结束------
  15. # 后台线程也应该随之结束

上面程序中的粗体字代码先将t线程设置成后台线程,然后启动该线程。本来该线程应该执行到i等于99时才会结束,但在运行程序时不难发现,该后台线程无法运行到99,因为当主线程也就是程序中唯一的前台线程运行结東后,程序会主动退出,所以后台线程也就被结東了。从上面的程序可以看出,主线程默认是前台线程,t线程默认也是前台线程。但并不是所有的线程默认都是前台线程,有些线程默认就是后台线程一一前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程

可见,创建后台线程有两种方式。

  1. 主动将线程的 daemon属性设置为True
  2. 后台线程启动的线程默认是后台线程。

以下看一个简单的多线程程序:

  1. import threading
  2. import time
  3. def coding():
  4. for x in range(3):
  5. print('%s正在写代码' % x)
  6. time.sleep(1)
  7. def drawing():
  8. for x in range(3):
  9. print('%s正在画图' % x)
  10. time.sleep(1)
  11. def single_thread():
  12. coding()
  13. drawing()
  14. def multi_thread():
  15. t1 = threading.Thread(target=coding)
  16. t2 = threading.Thread(target=drawing)
  17. t1.start()
  18. t2.start()
  19. if __name__ == '__main__':
  20. multi_thread()

继承自threading.Thread类:

为了让线程代码更好的封装。可以使用threading模块下的Thread类,继承自这个类,然后实现run方法,线程就会自动运行run方法中的代码。示例代码如下:

  1. import threading
  2. import time
  3. class CodingThread(threading.Thread):
  4. def run(self):
  5. for x in range(3):
  6. print('%s正在写代码' % threading.current_thread())
  7. time.sleep(1)
  8. class DrawingThread(threading.Thread):
  9. def run(self):
  10. for x in range(3):
  11. print('%s正在画图' % threading.current_thread())
  12. time.sleep(1)
  13. def multi_thread():
  14. t1 = CodingThread()
  15. t2 = DrawingThread()
  16. t1.start()
  17. t2.start()
  18. if __name__ == '__main__':
  19. 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锁实现的“生产者与消费者模式”的一个例子:

  1. import threading
  2. import random
  3. import time
  4. gMoney = 1000
  5. glo = threading.Lock()
  6. gTotaltime = 10
  7. gTime = 0
  8. class Consumer(threading.Thread):
  9. def run(self):
  10. global gMoney
  11. global gTime
  12. while True:
  13. money = random.randint(100,1000)
  14. glo.acquire()
  15. if gMoney>= money:
  16. gMoney -= money
  17. print("{}消费了{}元,当前剩余{}元".format(threading.current_thread(),money,gMoney))
  18. else:
  19. print("{}准备消费{}元,当前剩余{}元,不足,不能消费".format(threading.current_thread(),money,gMoney))
  20. if gTime >= gTotaltime and money > gMoney:
  21. glo.release()
  22. break
  23. glo.release()
  24. time.sleep(0.7)
  25. class Porducer(threading.Thread):
  26. def run(self):
  27. global gMoney
  28. global gTime
  29. while True:
  30. Money = random.randint(100,700)
  31. glo.acquire()
  32. if gTime == gTotaltime:
  33. glo.release()
  34. break
  35. gMoney += Money
  36. print("{}生产了{}元钱,剩余{}元钱".format(threading.current_thread(),Money,gMoney))
  37. gTime += 1
  38. glo.release()
  39. time.sleep(0.5)
  40. def main():
  41. for x in range(3):
  42. t1 = Porducer(name="生产者")
  43. t1.start()
  44. for i in range(5):
  45. t = Consumer(name="消费者")
  46. t.start()
  47. if __name__ == '__main__':
  48. main()

queue线程安全队列

在线程中,访问一些全局变量,加锁是一个经常的过程。如果你是想把一些数据存储到某个队列中,那么Python内置了一个线程安全的模块叫做queue模块。Python中的queue模块中提供了同步的、线程安全的队列类,包括FIFO(先进先出)队列Queue,LIFO(后入先出)队列LifoQueue。这些队列都实现了锁原语(可以理解为原子操作,即要么不做,要么都做完),能够在多线程中直接使用。可以使用队列来实现线程间的同步。相关的函数如下:

  1. 初始化Queue(maxsize):创建一个先进先出的队列。
  2. qsize():返回队列的大小。
  3. empty():判断队列是否为空。
  4. full():判断队列是否满了。
  5. get():从队列中取最后一个数据。
  6. put(item,block=Ture,timeout=None):将一个数据放到队列中。如果队列已满,且block参数为Ture(阻塞),当前线程被阻塞,timeout指定阻塞时间,如果将timeout设置为None,则代表一直阻塞,直到有元素被放入队列中:如果队列已空,且block参数设置为False(不阻塞),则直接引发queue.Empty异常。

    下面就可以用queue来进行线程通信
  1. import queue
  2. import time
  3. import threading
  4. def set_value(q):
  5. index = 0
  6. while True:
  7. q.put(index)
  8. index += 1
  9. time.sleep(3)
  10. def get_value(q):
  11. index = 0
  12. while True:
  13. print(q.get())
  14. time.sleep(0.5)
  15. def main():
  16. q = queue.Queue(4)
  17. t1 = threading.Thread(target=set_value,args=[q])
  18. t2 = threading.Thread(target=get_value,args=[q])
  19. t1.start()
  20. t2.start()
  21. if __name__ == '__main__':
  22. main()

python多线程+生产者和消费者模型+queue使用的更多相关文章

  1. Python之生产者&、消费者模型

    多线程中的生产者和消费者模型: 生产者和消费者可以用多线程实现,它们通过Queue队列进行通信. import time,random import Queue,threading q = Queue ...

  2. python:生产者与消费者模型

    1,生产者与消费者模型的矛盾在于数据供需的不平衡 import time import random from multiprocessing import Queue from multiproce ...

  3. 生产者、消费者模型---Queue类

    Queue队列在几乎每种编程语言都会有,python的列表隐藏的一个特点就是一个后进先出(LIFO)队列.而本文所讨论的Queue是python标准库queue中的一个类.它的原理与列表相似,但是先进 ...

  4. python queue和生产者和消费者模型

    queue队列 当必须安全地在多个线程之间交换信息时,队列在线程编程中特别有用. class queue.Queue(maxsize=0) #先入先出 class queue.LifoQueue(ma ...

  5. Python 之并发编程之进程下(事件(Event())、队列(Queue)、生产者与消费者模型、JoinableQueue)

    八:事件(Event()) # 阻塞事件:    e = Event() 生成事件对象e    e.wait() 动态给程序加阻塞,程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值 ...

  6. Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...

  7. 人生苦短之我用Python篇(队列、生产者和消费者模型)

    队列: queue.Queue(maxsize=0) #先入先出 queue.LifoQueue(maxsize=0) #last in fisrt out  queue.PriorityQueue( ...

  8. python并发编程之守护进程、互斥锁以及生产者和消费者模型

    一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...

  9. 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型

    关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...

随机推荐

  1. [Axure教程]0001.新手入门基础

    Axure RP是一个专业的快速原型设计工具.Axure(发音:Ack-sure),代表美国Axure公司:RP则是Rapid Prototyping(快速原型)的缩写.Axure RP已被一些大公司 ...

  2. Java IO(十九)PrintStream 和 PrintWriter

    Java IO(十九)PrintStream 和 PrintWriter 一.介绍 (一).PrintStream PrintStream 是打印输出流,它继承于FilterOutputStream. ...

  3. 附019.Rancher搭建及使用

    一 Rancher概述 1.1 什么是Rancher Rancher 是为使用容器的公司打造的容器管理平台.Rancher 简化了使用 Kubernetes 的流程,方便开发者可以随处运行 Kuber ...

  4. 微信小程序支付(企业支付给用户零钱)

    内容摘要:本案例客户端支付方式为微信小程序支付(JSAPI).商户运营一段时间后,在微信商户平台开通企业支付服务后,即可调用微信支付提供的企业付款接口将佣金等金额通过微信零钱返现给C端用户零钱. 服务 ...

  5. java实现洛谷P1308统计单词数

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  6. java实现第六届蓝桥杯奇怪的数列

    奇怪的数列 从X星截获一份电码,是一些数字,如下: 13 1113 3113 132113 1113122113 - YY博士经彻夜研究,发现了规律: 第一行的数字随便是什么,以后每一行都是对上一行& ...

  7. <Android> Location Service 分析

    由于各种原因,老师希望我学习Android系统源码以应对可能参与的项目.我只好深入曹营,刺探军情了. 定位服务是手机上最常用的功能之一,据说也是相对比较简单的服务,所以从这里入手.其他系统服务的架构都 ...

  8. Random Point in Triangle【随机数解决期望值问题】

    Random Point in Triangle 题目链接(点击) 题目描述 Bobo has a triangle ABC with A(x1,y1),B(x2,y2)A(x1,y1),B(x2,y ...

  9. 在CentOS8下利用seafile软件搭建私有云

    一.安装前准备工作 1. 安装EPEL源 EPEL (Extra Packages for Enterprise Linux)是基于Fedora的一个项目,为“红帽系”的操作系统提供额外的软件包,适用 ...

  10. Codeforces Round #648 (Div. 2)

    链接 : https://codeforces.com/contest/1365/problems problem A 统计可用的行和列的最小值, 模2输出即可 /* * Author: RoccoS ...