Python多线程原理与用法详解


Posted in Python onAugust 20, 2018

本文实例讲述了Python多线程原理与用法。分享给大家供大家参考,具体如下:

多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。[1] 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程(台湾译作“执行绪”),进而提升整体处理性能。

创建并启动一个线程

import threading
def runtask(name):
  print("%s线程已启动"%name)
t = threading.Thread(target=runtask,args=("task1",))  # args因为是一个元组,所以必须这样写,否则运行将报错
t.start()

join

等待当前线程执行完毕

import threading
import time
def runtask(name):
  print("%s线程已启动"%name)
  time.sleep(2)
t = threading.Thread(target=runtask,args=("task1",))
t.start()
t.join()
print("abc")  # 过了2s才会打印,若无等待将看不到等待2s的效果

setDaemon(True)

将线程设置为守护线程。若设置为守护线程,主线程结束后,子线程也将结束,并且主线程不会理会子线程是否结束,主线程不会等待子线程结束完后才结束。若没有设置为守护线程,主线程会等待子线程结束后才会结束。

active_count

程序的线程数量,数量=主线程+子线程数量

Lock(互斥锁)

Python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。在Python中我们使用threading模块提供的Lock类。

import threading,time
def runtask(name):
  global count
  time.sleep(1)
  lock.acquire()   # 获取锁资源,并返回是否获取成功
  count+=1
  print(name,count)
  lock.release()   # 释放资源
count = 0
lock = threading.Lock()   # 互斥锁
for index in range(50):
  t = threading.Thread(target=runtask,args=("thread%d"%index,))
  t.start()

上面这段代码如果没有加上互斥锁,在Python2.x中执行的结果将会是乱的。在Python3.x中执行却总是正确的,似乎是自动为其加了锁

RLock(递归锁,可重入锁)

当一个线程中遇到锁嵌套情况该怎么办,又会遇到什么情况?

def run1():
  global count1
  lock.acquire()
  count1 += 1
  lock.release()
  return count1
def run2():
  global count2
  lock.acquire()
  count2 += 1
  lock.release()
  return count2
def runtask():
  lock.acquire()
  r1 = run1()
  print("="*30)
  r2 = run2()
  lock.release()
  print(r1,r2)
count1,count2 = 0,0
lock = threading.Lock()
for index in range(50):
  t = threading.Thread(target=runtask,)
  t.start()

这是一个很简单的线程锁死案例,程序将被卡死,停止不动。为了解决这一情况,Python提供了递归锁RLock(可重入锁)。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的代码只需做一些小小的改动

lock = threading.Lock()

修改为:

lock = threading.RLock()

那么程序将不会发生死锁情况。

最大可执行线程

threading.BoundedSemaphore(5)设置可同时执行的最大线程数为5个,后面的线程需排队等待前面的线程执行完毕

import time,threading
def runtask(name):
  global num
  semaphore.acquire()
  time.sleep(1)
  num += 1
  semaphore.release()
  print(name,num)
num = 0
semaphore = threading.BoundedSemaphore(5)
for index in range(50):
  t = threading.Thread(target=runtask,args=("线程%s"%index,))
  t.start()

执行效果:

Python多线程原理与用法详解

可以看出上面的程序是每次只有5个线程在同时运行,其他线程需等待前面的线程执行完毕,这就是最大可执行线程。

Event

Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位为假,则线程等待直到信号被其他线程设置成真。Event中提供了四个重要的方法来满足基本的需求。

  • - clear:清除标记
  • - set:设置标记
  • - is_set:是否被标记
  • - wait:等待被标记

代码示例:

import threading,time
def lighter():
  num = 0
  event.set()   # 设置标记
  while True:
    if num >= 5 and num < 10:
      event.clear()  # 清除标记
      print("红灯亮起,车辆禁止通行")
    if num >= 10:
      event.set()   # 设置标记
      print("绿灯亮起,车辆可以通行")
      num = 0
    num += 1
    time.sleep(1)
def car():
  while True:
    if event.is_set():
      print("车辆正在跑...")
    else:
      print("车辆停下了")
      event.wait()
    time.sleep(1)
event = threading.Event()
t1 = threading.Thread(target=lighter,)
t2 = threading.Thread(target=car,)
t1.start()
t2.start()

这是一个简单的红灯停绿灯行案例。初始设置为绿灯并标记,车辆看到标记后通行,当红灯亮起的时候取消标记,车辆看到没有标记时停下,等待标记。

Queue队列

使任务按照某一种特定顺序有条不紊的进行。下面介绍几种常用的队列:

  • - queue.Queue():先进先出
  • - queue.LifoQueue():先进后出
  • - queue.PriorityQueue:优先级队列,优先级的值越小,越先执行

下面介绍几种常用的方法:

  • - get():获取item,如果队列已经取空将会卡住。可设置timeout参数,给定一个超时的值,或者设置参数block=False,队列空直接抛异常
  • - get_nowait():b获取item。如果队列取空了,将会直接抛异常
  • - put():放入队列
  • - empty():队列是否为空
  • - qsize():获取队列的item数量

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
小结Python用fork来创建子进程注意事项
Jul 03 Python
Python实现115网盘自动下载的方法
Sep 30 Python
Python HTMLParser模块解析html获取url实例
Apr 08 Python
python模块之sys模块和序列化模块(实例讲解)
Sep 13 Python
python提取图像的名字*.jpg到txt文本的方法
May 10 Python
Python实用技巧之列表、字典、集合中根据条件筛选数据详解
Jul 11 Python
对Python3中bytes和HexStr之间的转换详解
Dec 04 Python
代码详解django中数据库设置
Jan 28 Python
Python识别快递条形码及Tesseract-OCR使用详解
Jul 15 Python
Python greenlet和gevent使用代码示例解析
Apr 01 Python
python进度条显示之tqmd模块
Aug 22 Python
Python Serial串口基本操作(收发数据)
Nov 06 Python
Python模拟简单电梯调度算法示例
Aug 20 #Python
django_orm查询性能优化方法
Aug 20 #Python
Python Requests库基本用法示例
Aug 20 #Python
Django中使用第三方登录的示例代码
Aug 20 #Python
基于Django框架利用Ajax实现点赞功能实例代码
Aug 19 #Python
分析python请求数据
Aug 19 #Python
浅谈django orm 优化
Aug 18 #Python
You might like
PHP中实现进程间通讯
2006/10/09 PHP
php简单实现快速排序的方法
2015/04/04 PHP
php通过curl模拟登陆DZ论坛
2015/05/11 PHP
PHP反射原理与用法深入分析
2019/09/28 PHP
PHP pthreads v3下worker和pool的使用方法示例
2020/02/21 PHP
YUI的Tab切换实现代码
2010/04/11 Javascript
javascript创建数组之联合数组的使用方法示例
2013/12/26 Javascript
仿淘宝TAB切换搜索框搜索切换的相关内容
2014/09/21 Javascript
javascript操作表格排序实例分析
2015/05/06 Javascript
在JavaScript应用中实现延迟加载的方法
2015/06/25 Javascript
两款JS脚本判断手机浏览器类型跳转WAP手机网站
2015/10/16 Javascript
漂亮! js实现颜色渐变效果
2016/08/12 Javascript
15个非常实用的JavaScript代码片段
2016/12/18 Javascript
Vue数据驱动模拟实现3
2017/01/11 Javascript
js+html获取系统当前时间
2017/11/10 Javascript
angular动态表单制作
2018/02/23 Javascript
详解使用Nuxt.js快速搭建服务端渲染(SSR)应用
2019/03/13 Javascript
nodejs一个简单的文件服务器的创建方法
2019/09/13 NodeJs
Vue-resource安装过程及使用方法解析
2020/07/21 Javascript
[41:37]DOTA2北京网鱼队选拔赛——冲击职业之路
2015/04/13 DOTA
python中查看变量内存地址的方法
2015/05/05 Python
django批量导入xml数据
2016/10/16 Python
Python多进程multiprocessing.Pool类详解
2018/04/27 Python
python中selenium操作下拉滚动条的几种方法汇总
2019/07/14 Python
Python字符串中添加、插入特定字符的方法
2019/09/10 Python
python带参数打包exe及调用方式
2019/12/21 Python
Python高并发解决方案实现过程详解
2020/07/31 Python
利用Python发送邮件或发带附件的邮件
2020/11/12 Python
分享CSS3制作卡片式图片的方法
2016/07/08 HTML / CSS
工程技术员岗位职责
2014/03/02 职场文书
实习推荐信
2014/05/10 职场文书
小学语文教学经验交流材料
2014/06/02 职场文书
2015元旦晚会主持词(开场白+结束语)
2014/12/14 职场文书
认真学习保证书
2015/02/26 职场文书
结婚典礼主持词
2015/06/29 职场文书
Python实现排序方法常见的四种
2021/07/15 Python