一文速通 Python 并行计算:02 Python 多线程编程-threading 模块、线程的创建和查询与守护线程

摘要:

本文介绍了 Python threading 模块的核心功能,包括线程创建与管理、线程状态监控以及守护线程的特殊应用,重点讲解了 Thread 类的实例化方法、获取当前线程信息、检测线程存活状态,以及如何实现后台线程。

关于我们更多介绍可以查看云文档:Freak 嵌入式工作室云文档,或者访问我们的 wiki:****https://github.com/leezisheng/Doc/wik

原文链接:

FreakStudio的博客

往期推荐:

学嵌入式的你,还不会面向对象??!

全网最适合入门的面向对象编程教程:00 面向对象设计方法导论

全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念

全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类

全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性

全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法

全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签

全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装

全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系

全网最适合入门的面向对象编程教程:10 类和对象的Python实现-类的继承和里氏替换原则

全网最适合入门的面向对象编程教程:11 类和对象的Python实现-子类调用父类方法

全网最适合入门的面向对象编程教程:12 类和对象的Python实现-Python使用logging模块输出程序运行日志

全网最适合入门的面向对象编程教程:13 类和对象的Python实现-可视化阅读代码神器Sourcetrail的安装使用

全网最适合入门的面向对象编程教程:全网最适合入门的面向对象编程教程:14 类和对象的Python实现-类的静态方法和类方法

全网最适合入门的面向对象编程教程:15 类和对象的 Python 实现-__slots__魔法方法

全网最适合入门的面向对象编程教程:16 类和对象的Python实现-多态、方法重写与开闭原则

全网最适合入门的面向对象编程教程:17 类和对象的Python实现-鸭子类型与“file-like object“

全网最适合入门的面向对象编程教程:18 类和对象的Python实现-多重继承与PyQtGraph串口数据绘制曲线图

全网最适合入门的面向对象编程教程:19 类和对象的 Python 实现-使用 PyCharm 自动生成文件注释和函数注释

全网最适合入门的面向对象编程教程:20 类和对象的Python实现-组合关系的实现与CSV文件保存

全网最适合入门的面向对象编程教程:21 类和对象的Python实现-多文件的组织:模块module和包package

全网最适合入门的面向对象编程教程:22 类和对象的Python实现-异常和语法错误

全网最适合入门的面向对象编程教程:23 类和对象的Python实现-抛出异常

全网最适合入门的面向对象编程教程:24 类和对象的Python实现-异常的捕获与处理

全网最适合入门的面向对象编程教程:25 类和对象的Python实现-Python判断输入数据类型

全网最适合入门的面向对象编程教程:26 类和对象的Python实现-上下文管理器和with语句

全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现

全网最适合入门的面向对象编程教程:28 类和对象的Python实现-Python编程原则、哲学和规范大汇总

全网最适合入门的面向对象编程教程:29 类和对象的Python实现-断言与防御性编程和help函数的使用

全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类

全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type

全网最适合入门的面向对象编程教程:32 Python的内置数据类型-类Class和实例Instance

全网最适合入门的面向对象编程教程:33 Python的内置数据类型-对象Object和类型Type的关系

全网最适合入门的面向对象编程教程:34 Python的内置数据类型-Python常用复合数据类型:元组和命名元组

全网最适合入门的面向对象编程教程:35 Python的内置数据类型-文档字符串和__doc__属性

全网最适合入门的面向对象编程教程:36 Python的内置数据类型-字典

全网最适合入门的面向对象编程教程:37 Python常用复合数据类型-列表和列表推导式

全网最适合入门的面向对象编程教程:38 Python常用复合数据类型-使用列表实现堆栈、队列和双端队列

全网最适合入门的面向对象编程教程:39 Python常用复合数据类型-集合

全网最适合入门的面向对象编程教程:40 Python常用复合数据类型-枚举和enum模块的使用

全网最适合入门的面向对象编程教程:41 Python常用复合数据类型-队列(FIFO、LIFO、优先级队列、双端队列和环形队列)

全网最适合入门的面向对象编程教程:42 Python常用复合数据类型-collections容器数据类型

全网最适合入门的面向对象编程教程:43 Python常用复合数据类型-扩展内置数据类型

全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法

全网最适合入门的面向对象编程教程:45 Python实现常见数据结构-链表、树、哈希表、图和堆

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程:47 Python函数方法与接口-回调函数Callback

全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数

全网最适合入门的面向对象编程教程:49 Python函数方法与接口-函数与方法的区别和lamda匿名函数

全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类

全网最适合入门的面向对象编程教程:51 Python函数方法与接口-使用Zope实现接口

全网最适合入门的面向对象编程教程:52 Python函数方法与接口-Protocol协议与接口

全网最适合入门的面向对象编程教程:53 Python字符串与序列化-字符串与字符编码

全网最适合入门的面向对象编程教程:54 Python字符串与序列化-字符串格式化与format方法

全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串

全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用

全网最适合入门的面向对象编程教程:57 Python字符串与序列化-序列化与反序列化

全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现

全网最适合入门的面向对象编程教程:59 Python并行与并发-并行与并发和线程与进程

一文速通Python并行计算:00 并行计算的基本概念

一文速通Python并行计算:01 Python多线程编程-基本概念、切换流程、GIL锁机制和生产者与消费者模型

更多精彩内容可看:

给你的 Python 加加速:一文速通 Python 并行计算

一文搞懂 CM3 单片机调试原理

肝了半个月,嵌入式技术栈大汇总出炉

电子计算机类比赛的“武林秘籍”

一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库

Avnet ZUBoard 1CG开发板—深度学习新选择

工程师不要迷信开源代码,还要注重基本功

什么?配色个性化的电机驱动模块?!!

什么?XIAO主控新出三款扩展板!

手把手教你实现Arduino发布第三方库

万字长文手把手教你实现MicroPython/Python发布第三方库

文档获取:

可访问如下链接进行对文档下载:

https://github.com/leezisheng/Doc

该文档是一份关于 并行计算Python 并发编程 的学习指南,内容涵盖了并行计算的基本概念、Python 多线程编程、多进程编程以及协程编程的核心知识点:

正文

1.Python threading 模块

Python3 实现多线程编程需要借助于 threading 模块,threading 是 Python 标准库中的一个模块,它提供了一个高级的面向对象的线程编程接口。使用 threading 模块可以更方便地创建和管理线程,包括线程同步、线程通信、线程优先级等功能。(在 Python2 中,也有 thread 模块,它提供了一些基本的线程操作函数,例如 start_new_thread()函数用于创建新线程,exit()函数用于退出线程等。thread 模块只能在 Python 2 中使用。)

threading 模块包括以下组件:

  • (1)Thread 线程类,这是我们用的最多的一个类,你可以指定线程函数执行或者继承自它都可以实现子线程功能;
  • (2)Timer 与 Thread 类似,但要等待一段时间后才开始运行;
  • (3)Lock 锁,这个我们可以对全局变量互斥时使用;
  • (4)RLock 可重入锁,使单线程可以再次获得已经获得的锁;
  • (5)Condition 条件变量,能让一个线程停下来,等待其他线程满足某个“条件”;
  • (6)Event 通用的条件变量。多个线程可以等待某个事件发生,在事件发生后,所有的线程都被激活;
  • 7)Semaphore 为等待锁的线程提供一个类似“等候室”的结构;
  • (8)BoundedSemaphore 与 semaphore 类似,但不允许超过初始值;
  • (9)Queue:实现了多生产者(Producer)、多消费者(Consumer)的队列,支持锁原语,能够在多个线程之间提供很好的同步支持。

2.线程创建

使用线程最简单的一个方法是,用一个目标函数实例化一个 Thread 然后调用 start() 方法启动它。Python 的 threading 模块提供了 Thread() 方法在不同的线程中运行函数或处理过程等。

Thread 类代表一个在独立控制线程中运行的活动。该类提供的函数包括:

函数名称 作用
getName(self) 返回线程的名字
isAlive(self) 布尔标志,表示这个线程是否还在运行中
isDaemon(self) 返回线程的 daemon 标志
join(self, timeout=None) 程序挂起,直到线程结束,如果给出 timeout,则最多阻塞 timeout 秒
run(self) 定义线程的功能函数
setDaemon(self, daemonic) 用于设置线程是否为守护线程
setName(self, name) 设置线程的名字
start(self) 开始线程执行

一般来说,新建线程有两种模式,一种是创建线程要执行的函数,把这个函数传递进 Thread 对象里,让它来执行;另一种是直接从 Thread 继承,创建一个新的 class,把线程执行的代码放到这个新的 class 里。

2.1 调用 Thread 类的构造器创建线程

Thread 类提供了如下的 __init__() 构造器,可以用来创建线程:

__init__(self, group=None, target=None, name=None, args=(), kwargs=None, *,daemon=None)

此构造方法中,以上所有参数都是可选参数,即可以使用,也可以忽略。其中各个参数的含义如下:

  • group:指定所创建的线程隶属于哪个线程组;
  • target:当线程启动的时候要执行的函数;
  • name: 线程的名字,默认会分配一个唯一名字 Thread-N;
  • args:以元组的方式,为 target 指定的方法传递参数;
  • kwargs:以字典的方式,为 target 指定的方法传递参数;
  • daemon:指定所创建的线程是否为守护线程。

下面程序演示了如何使用 Thread 类的构造方法创建一个线程:

import threading
import time def test():
for i in range(5):
print('test ',i)
time.sleep(1)
thread = threading.Thread(target=test)
thread.start()
for i in range(5):
print('main ', i)
time.sleep(1)

上面代码很简单,在主线程上打印 5 次,在一个子线程上打印 5 次。

如下为代码输出,可以看到主线程和子线程交替执行:

2.2 继承 Thread 类创建线程类

通过继承 Thread 类,我们可以自定义一个线程类,从而实例化该类对象,获得子线程。需要注意的是,在创建 Thread 类的子类时,必须重写从父类继承得到的 run()方法。

import threading

_#创建子线程类,继承自 Thread 类_
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self);
_# 重写run()方法_
def run(self):
print("I am %s" % self.name) if __name__ == "__main__":
for thread in range(0, 5):
t = MyThread()
t.start()

这里,线程启动有 start()join() 两种方法。用 start() 方法来启动线程,真正实现了多线程运行,这时无需等待 run 方法体代码执行完毕而直接继续执行后面的代码。

通过调用 Thread 类的 start() 方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到 cpu 时间片,就开始执行 run() 方法;join() 让调用它的线程一直等待直到执行结束(即阻塞调用它的主线程, t 子线程执行结束,主线程才会继续执行)。

在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到 join()方法了。

这里,我们看一下使用 join() 方法启动线程:

import threading
_#定义线程要调用的方法,*add可接收多个以非关键字方式传入的参数_
def action(*add):
for arc in add:
_#调用 getName() 方法获取当前执行该程序的线程名_
print(threading.current_thread().name +" "+ arc)
_#定义为线程方法传入的参数_
my_tuple = ("http://c.biancheng.net/python/",\
"http://c.biancheng.net/shell/",\
"http://c.biancheng.net/java/")
_#创建线程_
thread = threading.Thread(target = action,args =my_tuple)
_#启动线程_
thread.start()
_#主线程执行如下语句_
for i in range(5):
print(threading.current_thread().name)

程序执行结果为(不唯一):

可以看到,我们用 Thread 类创建了一个线程(线程名为 Thread-1),其任务是执行 action() 函数。同时,我们也给主线程 MainThread 安排了循环任务(第 16、17 行)。通过前面的学习我们知道,主线程 MainThread 和子线程 Thread-1 会轮流获得 CPU 资源,因此该程序的输出结果才会向上面显示的这样。

但是,如果我们想让 Thread-1 子线程先执行,然后再让 MainThread 执行第 16、17 行代码,该如何实现呢?很简单,通过调用线程对象的 join() 方法即可。

join() 方法的功能是在程序指定位置,优先让该方法的调用者使用 CPU 资源。该方法的语法格式如下:thread.join( [timeout] )

其中,thread 为 Thread 类或其子类的实例化对象;timeout 参数作为可选参数,其功能是指定 thread 线程最多可以霸占 CPU 资源的时间(以秒为单位),如果省略,则默认直到 thread 执行结束(进入死亡状态)才释放 CPU 资源。

3.确定当前的线程

每一个 Thread 都有一个 name 的属性,代表的就是线程的名字,这个可以在构造方法中赋值。如果在构造方法中没有个 name 赋值的话,默认就是 “Thread-N” 的形式,N 是数字。通过 thread.current_thread() 方法可以返回线程本身,然后就可以访问它的 name 属性。

import threading
import time def test():
for i in range(5):
print(threading.current_thread().name+' test ',i)
time.sleep(1) thread = threading.Thread(target=test)
thread.start() for i in range(5):
print(threading.current_thread().name+' main ', i)
time.sleep(1)

如果我们在 Thread 对象创建时,构造方法里面赋值:

thread = threading.Thread(target=test,name='TestThread')

4.查询线程是否还在运行

Thread 具有生命周期,创建对象时,代表 Thread 内部被初始化;调用 start() 方法后,thread 会开始运行;thread 代码正常运行结束或者是遇到异常,线程会终止。

可以通过 Thread 的 is_alive()方法查询线程是否还在运行。值得注意的是,is_alive() 返回 True 的情况是 Thread 对象被正常初始化,start()方法被调用,然后线程的代码还在正常运行。

import threading
import time def test():
for i in range(5):
print(threading.current_thread().name+' test ',i)
time.sleep(0.5) thread = threading.Thread(target=test,name='TestThread')
_# thread = threading.Thread(target=test)_
thread.start() for i in range(5):
print(threading.current_thread().name+' main ', i)
print(thread.name+' is alive ', thread.is_alive())
time.sleep(1)

在上面的代码中,我们让 TestThread 比 MainThread 早一点结束,代码运行结果如下。

我们可以看到,主线程通过调用 TestThread 的 isAlive() 方法,准确查询到了它的存活状态。

5.守护线程的创建

Thread 的构造方法中有一个 daemon 参数。默认是 None。那么,daemon 起什么作用呢?我们先看一段示例代码。

import threading
import time def test():
for i in range(5):
print(threading.current_thread().name+' test ',i)
time.sleep(2) thread = threading.Thread(target=test,name='TestThread')
_# thread = threading.Thread(target=test,name='TestThread',daemon=True)_
thread.start() for i in range(5):
print(threading.current_thread().name+' main ', i)
print(thread.name+' is alive ', thread.is_alive())
time.sleep(1)

我们让主线程执行代码的时长比 TestThread 要短,程序运行结果如下:

MainThread 没有代码运行的时候,TestThread 还在运行。这是因为 MainThread 在等待其他线程的结束。TestThread 中 daemon 属性默认是 False,这使得 MainThread 需要等待它的结束,自身才结束。

如果要达到,MainThread 结束,子线程也立马结束,怎么做呢?其实很简单,只需要在子线程调用 start() 方法之前设置 daemon 就好了。当然也可以在子线程的构造器中传递 daemon 的值为 True。

修改

thread = threading.Thread(target=test,name='TestThread')

thread = threading.Thread(target=test,name='TestThread',daemon=True)

可以看到 MainThread 结束了 TestThread 也结束了。也可以用 setDaemon 方法使得只要主线程完成了,不管子线程是否完成,都要和主线程一起退出。

一文速通Python并行计算:02 Python多线程编程-threading模块、线程的创建和查询与守护线程的更多相关文章

  1. Python网络02 Python服务器进化

    原文:Python网络02 Python服务器进化 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! **注意,在Python 3. ...

  2. Python补充02 Python小技巧

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在这里列举一些我使用Python时积累的小技巧.这些技巧是我在使用Python过程 ...

  3. Python多线程(threading模块)

    线程(thread)是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. ...

  4. python基础之面向过程编程,模块

    面向过程编程 面向过程的核心是过程,指的是解决问题的步骤,即先干什么再干什么,就好像设计一条流水线. 优点:复杂的问题流程化,进而简单化 缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身 ...

  5. python多线程与threading模块

    python多线程与_thread模块 中介绍了线程的基本概念以及_thread模块的简单示例.然而,_thread模块过于简单,使得我们无法用它来准确地控制线程,本文介绍threading模块,它提 ...

  6. Python应用02 Python服务器进化

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! **注意,在Python 3.x中,BaseHTTPServer, SimpleH ...

  7. python并发编程-进程间通信-Queue队列使用-生产者消费者模型-线程理论-创建及对象属性方法-线程互斥锁-守护线程-02

    目录 进程补充 进程通信前言 Queue队列的基本使用 通过Queue队列实现进程间通信(IPC机制) 生产者消费者模型 以做包子买包子为例实现当包子卖完了停止消费行为 线程 什么是线程 为什么要有线 ...

  8. python多线程编程-queue模块和生产者-消费者问题

    摘录python核心编程 本例中演示生产者-消费者模型:商品或服务的生产者生产商品,然后将其放到类似队列的数据结构中.生产商品中的时间是不确定的,同样消费者消费商品的时间也是不确定的. 使用queue ...

  9. Python多线程的创建,相关函数和守护线程的理解

    一:多线程的创建 threading库创建线程有两种方式,函数式和继承式    1)函数式 def func(): print 'Starting' print 'Ending' t=threadin ...

  10. Python之多线程:Threading模块

    1.Threading模块提供的类 Thread,Lock,Rlock,Condition,Semaphore,Event,Timer,local 2.threading模块提供的常用的方法 (1)t ...

随机推荐

  1. 基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.1版已发布

    关于MobileIMSDK MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级.高度提炼,一套API优雅支持UDP .TCP .WebSocket 三种协议,支持iOS.A ...

  2. OpenMMLab AI实战营 第二课笔记 计算机视觉之图像分类算法基础

    OpenMMLab AI实战营 第二课笔记 目录 OpenMMLab AI实战营 第二课笔记 图像分类与基础视觉基础 1.图像分类问题 1.1 问题的数学表示 1.2 视觉任务的难点 1.2.1 超越 ...

  3. 前端学习openLayers配合vue3(获取矢量图的个数,省份的个数)

    矢量图层绘制了一个中国地图,我们获取一下矢量图层的个数 关键代码 map .getLayers()//获取所有图层 .item(1)//获取矢量图层 .getSource() .on("ch ...

  4. shell脚本检查192.168.1网段ip是否在用

    要检查 192.168.1 网段中哪些 IP 地址正在使用,可以使用 Shell 脚本结合 ping 命令来扫描整个网段.以下是实现这一功能的完整脚本: 脚本:检查 192.168.1 网段 IP 是 ...

  5. Mac上安装mongoDB详细教程

    Mac OSX 平台安装 MongoDB MongoDB 提供了 OSX 平台上 64 位的安装包,你可以在官网下载安装包. 下载地址:https://www.mongodb.com/download ...

  6. 使用 pdf.js 通过文件流方式加载pdf文件

    关于Pdf.js的基础知识,请参考我的博客  使用 pdf.js 在网页中加载 pdf 文件 使用 pdf.js 跨域问题的处理方法 上面两篇博客中介绍的内容都是基于直接加载远程服务器中静态PDF文件 ...

  7. threejs 实现镜面反射,只反射指定物体,背景透明

    一.背景 最近在做数字孪生项目,使用threejs渲染模型,UI要求地面反射建筑物,也就是模型要有倒影. 二.调研 在官网找到一个镜面反射的例子(https://threejs.org/example ...

  8. linux:lamp环境

    关于LAMP LAMP搭建 安装php和Apache 先装php,因为安装php有apache的依赖包 yum install php 启动Apache service httpd start 启动成 ...

  9. 载誉而归!天翼云荣获第23届中国IT用户满意度大会多项殊荣

    10月25日,2024第23届中国IT用户满意度大会暨首届工业产品满意度交流会在北京举行.现场揭晓"2024中国IT用户满意度征集结果",天翼云凭借领先的产品技术.完善的客户服务以 ...

  10. IDEA中创建Spring Boot项目(SSM框架)

    一.IDEA创建新Maven项目 创建maven项目完成 因为创建多模块项目,删除根目录src目录 二.maven多模块项目配置 需要创建的模块 umetric-web  控制层 umetric-we ...