Python多线程编程(一):threading 模块 Thread 类的用法详解

Python多线程编程(一):threading 模块 Thread 类的用法详解我们进行程序开发的时候 肯定避免不了要处理并发的情况 一般并发的手段有采用多进程和多线程 但线程比进程更轻量化 系统开销一般也更低 所以大家更倾向于用多线程的方式处理并发的情况 Python 提供多线程编程的方式 本文基于 Python3 讲解 Python 实现多线程编程需要借助于 threading 模块 所以 我们要在代码中引用它 importthread

我们进行程序开发的时候,肯定避免不了要处理并发的情况。

一般并发的手段有采用多进程和多线程。

但线程比进程更轻量化,系统开销一般也更低,所以大家更倾向于用多线程的方式处理并发的情况。

Python 提供多线程编程的方式。

本文基于 Python3 讲解,Python 实现多线程编程需要借助于 threading 模块。

所以,我们要在代码中引用它。

import threading 

threading 模块中最核心的内容是 Thread 这个类。

我们要创建 Thread 对象,然后让它们运行,每个 Thread 对象代表一个线程,在每个线程中我们可以让程序处理不同的任务,这就是多线程编程。

值得注意的是,程序运行时默认就是在主线程上

创建 Thread 对象有 2 种手段。

  1. 直接创建 Thread ,将一个 callable 对象从类的构造器传递进去,这个 callable 就是回调函数,用来处理任务。
  2. 编写一个自定义类继承 Thread,然后复写 run() 方法,在 run() 方法中编写任务处理代码,然后创建这个 Thread 的子类。

1. 直接创建 Thread 对象。

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={ 
   }, *, daemon=None) 

Thread 的构造方法中,最重要的参数是 target,所以我们需要将一个 callable 对象赋值给它,线程才能正常运行。

如果要让一个 Thread 对象启动,调用它的 start() 方法就好了。

下面是代码示例。

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 次。

运行结果如下:

test 0 main 0 main 1 test 1 main 2 test 2 main 3 test 3 main 4 test 4 

上面的 callable 没有参数,如果需要传递参数的话,args 是固定参数,kwargs 是可变参数。

Thread 的名字

每一个 Thread 都有一个 name 的属性,代表的就是线程的名字,这个可以在构造方法中赋值。

如果在构造方法中没有个 name 赋值的话,默认就是 “Thread-N” 的形式,N 是数字。

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.current_thread() 方法可以返回线程本身,然后就可以访问它的 name 属性。

上面代码运行结果如下:

Thread-1 test 0 MainThread main 0 Thread-1 test 1 MainThread main 1 Thread-1 test 2 MainThread main 2 Thread-1 test 3 MainThread main 3 Thread-1 test 4 MainThread main 4 

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

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

那么,运行结果会变成这个样子。

TestThread test 0 MainThread main 0 MainThread main 1 TestThread test 1 MainThread main 2 TestThread test 2 MainThread main 3 TestThread test 3 MainThread main 4 TestThread test 4 

Thread 的生命周期

  1. 创建对象时,代表 Thread 内部被初始化。
  2. 调用 start() 方法后,thread 会开始运行。
  3. 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.isAlive()) time.sleep(1) 

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

TestThread test 0 MainThread main 0 TestThread is alive True TestThread test 1 MainThread main 1 TestThread is alive True TestThread test 2 TestThread test 3 MainThread main 2 TestThread is alive True TestThread test 4 MainThread main 3 TestThread is alive False MainThread main 4 TestThread is alive False 

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

join() 提供线程阻塞手段。

上面代码两个线程是同时运行的,但如果让一个先运行,一个后运行,怎么做呢?

调用一个 Thread 的 join() 方法,可以阻塞自身所在的线程。

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.start() thread.join() for i in range(5): print(threading.current_thread().name+' main ', i) print(thread.name+' is alive ', thread.isAlive()) time.sleep(1) 

主线程创建了 TestThread 对象后,让其 start,然后通过调用 join() 方法,实现等待。程序运行结果如下:

TestThread test 0 TestThread test 1 TestThread test 2 TestThread test 3 TestThread test 4 MainThread main 0 TestThread is alive False MainThread main 1 TestThread is alive False MainThread main 2 TestThread is alive False MainThread main 3 TestThread is alive False MainThread main 4 TestThread is alive False 

默认的情况是,join() 会一直等待对应线程的结束,但可以通过参数赋值,等待规定的时间就好了。

def join(self, timeout=None): 

timeout 是一个浮点参数,单位是秒。

如果我们更改上面的代码。

thread.join(1.0) 

它的结果会是这样。

TestThread test 0 TestThread test 1 MainThread main 0 TestThread is alive True TestThread test 2 TestThread test 3 MainThread main 1 TestThread is alive True TestThread test 4 MainThread main 2 TestThread is alive False MainThread main 3 TestThread is alive False MainThread main 4 TestThread is alive False 

主线程只等待了 1 秒钟。

Thread 中的 daemon 属性

有同学可能会注意到,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.isAlive()) time.sleep(1) 

我们让主线程执行代码的时长比 TestThread 要短。

程序运行结果如下。

TestThread test 0 MainThread main 0 TestThread is alive True MainThread main 1 TestThread is alive True TestThread test 1 MainThread main 2 TestThread is alive True MainThread main 3 TestThread is alive True TestThread test 2 MainThread main 4 TestThread is alive True TestThread test 3 TestThread test 4 

MainThread 没有代码运行的时候,TestThread 还在运行。

这是因为 MainThread 在等待其他线程的结束。

TestThread 中 daemon 属性默认是 False,这使得 MainThread 需要等待它的结束,自身才结束。

如果要达到,MainThread 结束,子线程也立马结束,怎么做呢?

其实很简单,只需要在子线程调用 start() 方法之前设置 daemon 就好了。

当然也可以在子线程的构造器中传递 daemon 的值为 True。

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

更改前面代码示例,运行结果如下

TestThread test 0 MainThread main 0 TestThread is alive True MainThread main 1 TestThread is alive True TestThread test 1 MainThread main 2 TestThread is alive True MainThread main 3 TestThread is alive True TestThread test 2 MainThread main 4 TestThread is alive True 

可以看到 MainThread 结束了 TestThread 也结束了。

2.自定义类继承 Thread

前面讲过,直接初始化一个 Thread,然后,现在还有一种方式就是自定义一个 Thread 的子类,然后复写它的 run() 方法。

import threading import time class TestThread(threading.Thread): def __init__(self,name=None): threading.Thread.__init__(self,name=name) def run(self): for i in range(5): print(threading.current_thread().name + ' test ', i) time.sleep(1) thread = TestThread(name='TestThread') thread.start() for i in range(5): print(threading.current_thread().name+' main ', i) print(thread.name+' is alive ', thread.isAlive()) time.sleep(1) 

上面的代码,我们自定义了 TestThread 这个类,然后继承了 threading.Thread。

只有在 run() 方法中处理逻辑。最终代码运行结果如下:

TestThread test 0 MainThread main 0 TestThread is alive True TestThread test 1 MainThread main 1 TestThread is alive True TestThread test 2 MainThread main 2 TestThread is alive True MainThread main 3 TestThread is alive True TestThread test 3 MainThread main 4 TestThread test 4 TestThread is alive True 

这与之前的效果并无差异,但我还是推荐用这种方法,毕竟面向对象编程嘛。

自此,Python 多线程编码技术就大致介绍完毕,大家可以进行实际代码编写了。

但是,多线程编程的难点在于多个线程之间共享数据的同步,这是非常容易出错的地方,我将分别编写相应的博文去介绍一些高级的技术点。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214059.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午5:04
下一篇 2026年3月18日 下午5:05


相关推荐

  • 导航和渲染首页文章列表

    导航和渲染首页文章列表

    2021年6月30日
    93
  • 从零开始学习UCOSII操作系统13–系统移植理论篇「建议收藏」

    从零开始学习UCOSII操作系统13–系统移植理论篇「建议收藏」从零开始学习UCOSII操作系统13–系统移植理论篇1、什么是系统移植?(1)UCOSII移植到不同的处理器上,所谓的移植就是将一个实时的内核能在其他的微处理器或者微控制器上运行。为了方便移植,UCOSII的大部分的代码都是C语言写的,因为不同机器的汇编代码是不一样的。这是由于UCOSII在设计的时候已经充分考虑到了可移植性这一点。但是仍然有一部分的代码是需要用C语言

    2022年5月4日
    42
  • C++——随机数算法

    C++——随机数算法前言:在这里,我们要明确,计算机随机化出来的数字都是伪随机数字,就是近似于随机数,简单来说这个伪随机数需要依靠一个种子来决定这个数值的大小。默认情况下,这个种子的值是1。这造成了如果不改变种子的值,我们生成的随机数就会是同一个值。所以,我们就要设置种子C语言版本在C语言里,产生随机数主要用上两个函数,一个是srand(),另外一个是rand()函数。这个也没啥介绍的,具体看代码,就传递几个参数。rand()函数会返回一个范围在0到RAND_MAX(至少是32767,我的机器上是int的最大值)之间的

    2022年7月14日
    13
  • 怎么使用 eclipse 开发和运行 Java 程序呢?

    怎么使用 eclipse 开发和运行 Java 程序呢?·使用eclipse开发第一个程序我们在上一节建好的Java项目中,开始开发Java程序。首先,新建一个Java类。在src目录上右键单击,建立一个Java类。如图1所示。图1新建Java类入口出现新建类的开始界面,如图2所示。我们只需输入类名即可,其他不需做任何设置:图2指定Java类的名称点击Finish后,新建Java类成功,出现如图3所示。图3新建Java类完成在src下面出现了Welcome.java文件。点击该文件

    2022年7月9日
    23
  • coze开发 | coze智能体和 AI 应用从入门到精通 (保姆式教程)

    coze开发 | coze智能体和 AI 应用从入门到精通 (保姆式教程)

    2026年3月12日
    5
  • bios刷写工具_蓝天P750/P751编程器刷BIOS「建议收藏」

    bios刷写工具_蓝天P750/P751编程器刷BIOS「建议收藏」神舟ZX8-SP7是蓝天P751DM2模具,今天在WIN下刷BIOS成功刷黑,开始使用编程器刷BIOS,笔记本BIOS芯片由于是焊在主板上必须用夹子或者脱焊后用烧录座刷写,所以需要买编程器夹子。工具:优硕EZP-XPROV2、优硕SOP8编程器夹子。目标:神舟ZX8-SP7(P751DM2模具)准备工作:去蓝天镜像站下载对应的模具的BIOS蓝天镜像站:https://repo.palkeo.co…

    2022年6月26日
    167

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号