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操作列表的常用方法分享
Feb 13 Python
python实现应用程序在右键菜单中添加打开方式功能
Jan 09 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
Nov 11 Python
Python实现带参数与不带参数的多重继承示例
Jan 30 Python
Tensorflow之构建自己的图片数据集TFrecords的方法
Feb 07 Python
Python简单实现查找一个字符串中最长不重复子串的方法
Mar 26 Python
Python实现绘制双柱状图并显示数值功能示例
Jun 23 Python
python的schedule定时任务模块二次封装方法
Feb 19 Python
详解如何设置Python环境变量?
May 13 Python
在python下使用tensorflow判断是否存在文件夹的实例
Jun 10 Python
python 密码学示例——凯撒密码的实现
Sep 21 Python
python简单验证码识别的实现过程
Jun 20 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的ASP防火墙
2006/10/09 PHP
php+AJAX传送中文会导致乱码的问题的解决方法
2008/09/08 PHP
php的$_FILES的临时储存文件与回收机制实测过程
2013/07/12 PHP
php实现可用于mysql,mssql,pg数据库操作类
2014/12/13 PHP
Zend Framework动作助手Redirector用法实例详解
2016/03/05 PHP
详解PHP编码转换函数应用技巧
2016/10/22 PHP
PHP + plupload.js实现多图上传并显示进度条加删除实例代码
2017/03/06 PHP
PHP实现的敏感词过滤方法示例
2019/03/06 PHP
CentOS7编译安装php7.1的教程详解
2019/04/18 PHP
laradock环境docker-compose操作详解
2019/07/29 PHP
js中onload与onunload的使用示例
2013/08/25 Javascript
javascript简单实现表格行间隔显示颜色并高亮显示
2013/11/29 Javascript
jQuery实现新消息闪烁标题提示的方法
2015/03/11 Javascript
jquery实现的Accordion折叠面板效果代码
2015/09/02 Javascript
原生JS实现平滑回到顶部组件
2016/03/16 Javascript
jQuery获取父元素及父节点的方法小结
2016/04/14 Javascript
全面了解addEventListener和on的区别
2016/07/14 Javascript
JavaScript 中 avalon绑定属性总结
2016/10/19 Javascript
jQuery使用ajax方法解析返回的json数据功能示例
2017/01/10 Javascript
JS实现京东首页之页面顶部、Logo和搜索框功能
2017/01/12 Javascript
nodeJS(express4.x)+vue(vue-cli)构建前后端分离实例(带跨域)
2017/07/05 NodeJs
JavaScript去掉数组重复项的方法分析【测试可用】
2018/07/19 Javascript
javaScript 实现重复输出给定的字符串的常用方法小结
2020/02/20 Javascript
vue-cli3项目配置eslint代码规范的完整步骤
2020/09/10 Javascript
解决antd 下拉框 input [defaultValue] 的值的问题
2020/10/31 Javascript
js调用网络摄像头的方法
2020/12/05 Javascript
仅用500行Python代码实现一个英文解析器的教程
2015/04/02 Python
几个适合python初学者的简单小程序,看完受益匪浅!(推荐)
2019/04/16 Python
连接pandas以及数组转pandas的方法
2019/06/28 Python
Django中ORM找出内容不为空的数据实例
2020/05/20 Python
Python threading模块condition原理及运行流程详解
2020/10/05 Python
瑞典首都斯德哥尔摩的多元奢侈时尚品牌:Acne Studios
2017/07/09 全球购物
应届硕士毕业生自荐信
2014/05/26 职场文书
python编程学习使用管道Pipe编写优化代码
2021/11/20 Python
nginx共享内存的机制详解
2022/03/21 Servers
python中redis包操作数据库的教程
2022/04/19 Python