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双向链表实现实例代码
Nov 21 Python
Python简单日志处理类分享
Feb 14 Python
win10系统中安装scrapy-1.1
Jul 03 Python
Python 实现12306登录功能实例代码
Feb 09 Python
Python3.6笔记之将程序运行结果输出到文件的方法
Apr 22 Python
python实现指定文件夹下的指定文件移动到指定位置
Sep 17 Python
使用Python开发SQLite代理服务器的方法
Dec 07 Python
python中对_init_的理解及实例解析
Oct 11 Python
Python csv文件的读写操作实例详解
Nov 19 Python
Python Celery多队列配置代码实例
Nov 22 Python
python3让print输出不换行的方法
Aug 24 Python
Python如何telnet到网络设备
Feb 18 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设计模式 Factory(工厂模式)
2011/06/26 PHP
保存到桌面、设为桌面且带图标的PHP代码
2013/11/19 PHP
php cli换行示例
2014/04/22 PHP
ThinkPHP单字母函数(快捷方法)使用总结
2014/07/23 PHP
php中get_meta_tags()、CURL与user-agent用法分析
2014/12/16 PHP
JavaScript 仿关机效果的图片层
2008/12/26 Javascript
javascript GUID生成器实现代码
2009/10/31 Javascript
js单例模式详解实例
2013/11/21 Javascript
javascript中的undefined和not defined区别示例介绍
2014/02/26 Javascript
jQuery插件Elastislide实现响应式的焦点图无缝滚动切换特效
2015/04/12 Javascript
javascript实现在网页任意处点左键弹出隐藏菜单的方法
2015/05/13 Javascript
拥有一个属于自己的javascript表单验证插件
2016/03/24 Javascript
EasyUi combotree 实现动态加载树节点
2016/04/01 Javascript
AngularJS基础 ng-non-bindable 指令详细介绍
2016/08/02 Javascript
jQuery日程管理控件glDatePicker用法详解
2017/03/29 jQuery
JavaScript mixin实现多继承的方法详解
2017/03/30 Javascript
vue初始化动画加载的实例
2018/09/01 Javascript
用npm安装vue和vue-cli,并使用webpack创建项目的方法
2018/09/28 Javascript
VUE基于NUXT的SSR 服务端渲染
2018/11/30 Javascript
微信小程序自定义弹窗实现详解(可通用)
2019/07/04 Javascript
[04:03]DOTA2英雄梦之声_第02期_风暴之灵
2014/06/30 DOTA
[01:09:20]NB vs NAVI Supermajor小组赛A组 BO3 第二场 6.2
2018/06/03 DOTA
Python实现mysql数据库更新表数据接口的功能
2017/11/19 Python
python如何提升爬虫效率
2020/09/27 Python
HTML5中canvas中的beginPath()和closePath()的重要性
2018/08/24 HTML / CSS
YesStyle美国/全球:购买亚洲时装、美容化妆品和生活百货
2017/01/16 全球购物
工程专业求职自荐书范文
2014/02/18 职场文书
《老王》教学反思
2014/02/23 职场文书
我爱我校演讲稿
2014/05/21 职场文书
文明寝室标语
2014/06/13 职场文书
银行授权委托书样本
2014/10/13 职场文书
工作业绩不及格检讨书
2014/10/28 职场文书
学习党章的体会
2014/11/07 职场文书
酒店工程部经理岗位职责
2015/04/09 职场文书
2015年检验科工作总结
2015/04/27 职场文书
预备党员党支部意见
2015/06/02 职场文书