python多线程使用方法实例详解


Posted in Python onDecember 30, 2019

本文实例讲述了python多线程使用方法。分享给大家供大家参考,具体如下:

threading 模块支持守护线程, 其工作方式是:守护线程一般是一个等待客户端请求服务的服务器。

如果把一个线程设置为守护线程,进程退出时不需要等待这个线程执行完成。

如果主线程准备退出时,不需要等待某些子线程完成,就可以为这些子线程设置守护线程标记。 需要在启动线程之前执行如下赋值语句: thread.daemon = True,检查线程的守护状态也只需要检查这个值即可。

整个 Python 程序将在所有非守护线程退出之后才退出, 换句话说, 就是没有剩下存活的非守护线程时才退出。

使用thread模块

以下是三种使用 Thread 类的方法(一般使用第一个或第三个方案)

  • 创建 Thread 的实例,传给它一个函数。
import threading
from time import sleep, ctime
loops = [3, 2, 1, 1, 1]
def loop(i, nsec):
  print(f'start loop {i} at: {ctime()}')
  sleep(nsec)
  print(f'end loop {i} at: {ctime()}')
def main():
  print('start at', ctime())
  threads = []
  nloops = range(len(loops))
  for i in nloops:
    t = threading.Thread(target=loop, args=(i, loops[i]))
    threads.append(t)
  for i in nloops: # start threads
    threads[i].start()
  for i in nloops: # wait for all
    threads[i].join() # threads to finish
  print(f'all done at: {ctime()}')
if __name__ == '__main__':
  main()

当所有线程都分配完成之后,通过调用每个线程的 start()方法让它们开始执行,而不是 在这之前就会执行。
相比于管理一组锁(分配、获取、释放、检查锁状态等)而言,这里只 需要为每个线程调用 join()方法即可。
join()方法将等待线程结束,或者在提供了超时时间的情况下,达到超时时间。
使用 join()方法要比等待锁释放的无限循环更加清晰(这也是这种锁 又称为自旋锁的原因)。

  • 创建 Thread 的实例,传给它一个可调用的类实例。
import threading
from time import sleep, ctime
# 创建 Thread 的实例,传给它一个可调用的类实例
loops = [3, 2, 1, 1, 1]
class ThreadFunc(object):
  def __init__(self, func, args, name=''):
    self.name = name
    self.func = func
    self.args = args
  def __call__(self):
    self.func(*self.args)
def loop(i, nsec):
  print(f'start loop {i} at: {ctime()}')
  sleep(nsec)
  print(f'end loop {i} at: {ctime()}')
def main():
  print('start at', ctime())
  threads = []
  nloops = range(len(loops))
  for i in nloops:
    t = threading.Thread(target=ThreadFunc(loop, (i, loops[i]), loop.__name__))
    threads.append(t)
  for i in nloops: # start threads
    threads[i].start()
  for i in nloops: # wait for all
    threads[i].join() # threads to finish
  print(f'all done at: {ctime()}')
if __name__ == '__main__':
  main()
  • 派生 Thread 的子类,并创建子类的实例。
import threading
from time import sleep, ctime
# 创建 Thread 的实例,传给它一个可调用的类实例
# 子类的构造函数必须先调用其基类的构造函数
# 特殊方法__call__()在 子类中必须要写为 run()
loops = [3, 2, 1, 1, 1]
class MyThread(threading.Thread):
  def __init__(self, func, args, name=''):
    threading.Thread.__init__(self)
    self.name = name
    self.func = func
    self.args = args
  def run(self):
    self.func(*self.args)
def loop(i, nsec):
  print(f'start loop {i} at: {ctime()}')
  sleep(nsec)
  print(f'end loop {i} at: {ctime()}')
def main():
  print('start at', ctime())
  threads = []
  nloops = range(len(loops))
  for i in nloops:
    t = MyThread(loop, (i, loops[i]), loop.__name__)
    threads.append(t)
  for i in nloops: # start threads
    threads[i].start()
  for i in nloops: # wait for all
    threads[i].join() # threads to finish
  print(f'all done at: {ctime()}')
if __name__ == '__main__':
  main()

使用锁

python和java一样,也具有锁机制,而且创建与使用锁都是很简便的。

一般在多线程代码中,总会有一些特 定的函数或代码块不希望(或不应该)被多个线程同时执行,通常包括修改数据库、更新文件或 其他会产生竞态条件的类似情况

锁有两种状态:锁定和未锁定。而且它也只支持两个函数:获得锁和释放锁。

一般锁的调用如下

# 加载线程的锁对象
lock = threading.Lock()
# 获取锁
lock.acquire()
# ...代码
# 释放锁
lock.release()

更简洁的方法是使用with关键字,如下代码功能同上

# 加载线程的锁对象
lock = threading.Lock()
with lock :
  #...代码

示例代码:

import threading
from time import sleep, ctime
lock = threading.Lock()
def a():
  lock.acquire()
  for x in range(5):
    print(f'a:{str(x)}')
    sleep(0.01)
  lock.release()
def b():
  lock.acquire()
  for x in range(5):
    print(f'a:{str(x)}')
    sleep(0.01)
  lock.release()
threading.Thread(target=a).start()
threading.Thread(target=b).start()

相关属性和方法

  • Thread对象的属性

属性 描述
name 线程名
ident 线程的标识符
daemon 布尔标志,表示这个线程是否是守护线程
 
  • Thread对象的方法

方法 描述
init(group=None, tatget=None, name=None, args=(), kwargs ={}, verbose=None, daemon=None) 实例化一个线程对象,需要有一个可调用的 target,以及其参数 args 或 kwargs。还可以传递 name 或 group 参数,不过后者还未实现。此 外 , verbose 标 志 也 是 可 接 受 的 。 而 daemon 的 值 将 会 设 定 thread.daemon 属性/标志
start() 开始执行该线程
run() 定义线程功能的方法(通常在子类中被应用开发者重写)
join (timeout=None) 直至启动的线程终止之前一直挂起;除非给出了 timeout(秒),否则 会一直阻塞
is_alive() 布尔标志,表示这个线程是否还存活
  • threading模块其他函数

函数 描述
start() 开始执行该线程
active_count() 当前活动的 Thread 对象个数
enumerate() 返回当前活动的 Thread 对象列表
settrace(func) 为所有线程设置一个 trace 函数
setprofile (func) 为所有线程设置一个 profile 函数
stack_size(size=0) 返回新创建线程的栈大小;或为后续创建的线程设定栈的大小 为 size
Lock() 加载线程的锁对象,是一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取,对象有acquire()和release()方法
RLock() 多重锁,在同一线程中可用被多次acquire。如果使用RLock,那么acquire和release必须成对出现,调用了n次acquire锁请求,则必须调用n次的release才能在线程中释放锁对象

后记

在Python多线程下,每个线程的执行方式:

1、获取GIL
2、执行代码直到sleep或者是python虚拟机将其挂起。
3、释放GIL

通常来说,多线程是一个好东西。不过由于 Python 的 GIL 的限制,多线程更适合于 I/O 密集型应用(I/O 释放了 GIL,可以允 许更多的并发),而不是计算密集型应用。对于后一种情况而言,为了实现更好的并行性,你需要使用多进程,以便让 CPU 的其他内核来执行。

请注意:多核多线程比单核多线程更差,原因是单核下多线程,每次释放GIL,唤醒的那个线程都能获取到GIL锁,所以能够无缝执行,但多核下,CPU0释放GIL后,其他CPU上的线程都会进行竞争,但GIL可能会马上又被CPU0拿到,导致其他几个CPU上被唤醒后的线程会醒着等待到切换时间后又进入待调度状态,这样会造成线程颠簸(thrashing),导致效率更低

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

Python 相关文章推荐
py中的目录与文件判别代码
Jul 16 Python
python动态参数用法实例分析
May 25 Python
基于Python实现定时自动给微信好友发送天气预报
Oct 25 Python
PyQt5实现从主窗口打开子窗口的方法
Jun 19 Python
python 杀死自身进程的实现方法
Jul 01 Python
python实现控制电脑鼠标和键盘,登录QQ的方法示例
Jul 06 Python
python实现的自动发送消息功能详解
Aug 15 Python
Python实现二叉树的最小深度的两种方法
Sep 30 Python
Python简易计算器制作方法代码详解
Oct 31 Python
pytorch 图像预处理之减去均值,除以方差的实例
Jan 02 Python
如何在keras中添加自己的优化器(如adam等)
Jun 19 Python
Python中requests库的用法详解
Jun 05 Python
Python动态声明变量赋值代码实例
Dec 30 #Python
使用pytorch实现可视化中间层的结果
Dec 30 #Python
在Pytorch中计算自己模型的FLOPs方式
Dec 30 #Python
Pytorch之保存读取模型实例
Dec 30 #Python
Python爬虫解析网页的4种方式实例及原理解析
Dec 30 #Python
Python中如何将一个类方法变为多个方法
Dec 30 #Python
pytorch 实现打印模型的参数值
Dec 30 #Python
You might like
mysql+php分页类(已测)
2008/03/31 PHP
PHP中对用户身份认证实现两种方法
2011/06/04 PHP
PHP在线生成二维码代码(google api)
2013/06/03 PHP
PHP实现文件上传下载实例
2016/10/18 PHP
PHP解决中文乱码
2017/04/28 PHP
PHP封装curl的调用接口及常用函数详解
2018/05/31 PHP
PHP+iframe模拟Ajax上传文件功能示例
2019/07/02 PHP
正则表达式判断是否存在中文和全角字符和判断包含中文字符串长度
2008/09/27 Javascript
jquery 插件 任意位置浮动固定层
2008/12/25 Javascript
ie和firefox不兼容的解决方法集合
2009/04/28 Javascript
jQuery事件之键盘事件(ctrl+Enter回车键提交表单等)
2014/05/11 Javascript
JQuery性能优化的几点建议
2014/05/14 Javascript
javascript中的this详解
2014/12/08 Javascript
MVVM模式中ViewModel和View、Model有什么区别?
2015/06/19 Javascript
JavaScript html5 canvas绘制时钟效果
2016/03/01 Javascript
Bootstrap编写一个在当前网页弹出可关闭的对话框 非弹窗
2016/06/30 Javascript
百度搜索框智能提示案例jsonp
2016/11/28 Javascript
详解react-router如何实现按需加载
2017/06/15 Javascript
webpack 2.x配置reactjs基本开发环境详解
2017/08/08 Javascript
javascript实现QQ空间相册展示源码
2017/12/12 Javascript
JS实现延迟隐藏功能的方法(类似QQ头像鼠标放上展示信息)
2017/12/28 Javascript
React-native桥接Android原生开发详解
2018/01/17 Javascript
p5.js 毕达哥拉斯树的实现代码
2018/03/23 Javascript
bootstrap treeview 树形菜单带复选框及级联选择功能
2018/06/08 Javascript
小程序显示弹窗时禁止下层的内容滚动实现方法
2019/03/20 Javascript
深入理解基于vue-cli的webpack打包优化实践及探索
2019/10/14 Javascript
vue中@change兼容问题详解
2019/10/25 Javascript
使用Python编写提取日志中的中文的脚本的方法
2015/04/30 Python
jupyter notebook 中输出pyecharts图实例
2020/04/23 Python
PyTorch中反卷积的用法详解
2019/12/30 Python
使用python对excel表格处理的一些小功能
2021/01/25 Python
CSS3实现线性渐变用法示例代码详解
2020/08/07 HTML / CSS
施华洛世奇韩国官网:SWAROVSKI韩国
2018/06/05 全球购物
2016高考感言
2015/08/01 职场文书
一文弄懂MySQL索引创建原则
2022/02/28 MySQL
收音机爱好者玩机13年,简评其使用过的19台收音机
2022/04/30 无线电