摘要:本文介绍了Python中实现线程的两种方式:_thread模块和threading模块。_thread模块提供基本线程操作,而threading模块采用面向对象设计,功能更丰富。文章详细说明了如何创建线程、线程状态转换以及守护线程的实现,并通过示例代码演示了线程的创建、运行和终止过程。重点对比了_thread.start_new_thread()方法和threading.Thread类的使用方式,同时讲解了守护线程的特性及其适用场景。

目录

Python 中的并发 —— 线程的实现

实现线程的 Python 模块

<_thread> 模块

示例

输出结果

模块

模块的额外方法

如何通过 模块创建线程?

示例

输出结果

演示线程各状态的 Python 程序

步骤 1:导入所需模块 threading 和 time

步骤 2:定义线程执行的目标函数

步骤 3:通过 time 模块的 sleep () 方法,让线程等待 2 秒

步骤 4:创建线程实例 T1,指定执行的目标函数

步骤 5:调用 start () 方法启动线程,控制台将打印预设的运行状态提示

步骤 6:线程执行完毕后,调用 join () 方法回收线程资源(终止线程)

Python 中启动线程的简易方式

输出结果

Python 中的守护线程


Python 中的并发 —— 线程的实现

实现线程的 Python 模块

Python 中的线程也被称作轻量级进程,因为线程占用的内存远少于进程,且能支持程序同时执行多个任务。Python 中提供了两个实现线程的核心模块,分别是:

  • <_thread> 模块
  • <threading> 模块

两个模块的核心区别在于:<_thread> 模块将线程视作一个函数来处理,而 **<threading>** 模块采用面向对象的设计思路,把每个线程都封装为一个对象;此外,<_thread> 模块仅适用于底层线程操作,功能远不如 **<threading>** 模块丰富。

<_thread> 模块

在 Python 早期版本中,提供的是 **<thread>** 模块,但该模块已被标记为 “废弃” 许久,官方一直推荐开发者使用 **<threading>** 模块替代。因此在 Python 3 中,thread 模块被彻底移除,为了兼容版本差异,重命名为 **<_thread>** 模块。

通过 <_thread> 模块创建新线程时,需要调用其start_new_thread 方法,该方法的语法格式如下:

_thread.start_new_thread ( function, args[, kwargs] )

参数说明:

  • args:传入函数的参数,以元组形式传递
  • kwargs:可选参数,以字典形式为函数传递关键字参数

如果调用的函数无需传入参数,需将args 设置为空元组。

该方法调用后会立即返回,子线程随即启动,并将参数(若有)传入指定函数执行。当函数执行完毕后,对应的子线程也会随之终止。

示例

以下示例通过 <_thread> 模块的 start_new_thread() 方法创建新线程:

import _thread
import time

def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print ("%s: %s" % ( threadName, time.ctime(time.time()) ))

try:
   _thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   _thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print ("Error: unable to start thread")

while 1:
   pass
输出结果

以下输出能清晰体现 <_thread> 模块创建的多线程执行过程:

plaintext

Thread-1: Mon Apr 23 10:03:33 2018
Thread-2: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:37 2018
Thread-2: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:41 2018
Thread-2: Mon Apr 23 10:03:43 2018
Thread-2: Mon Apr 23 10:03:47 2018
Thread-2: Mon Apr 23 10:03:51 2018

<threading> 模块

<threading> 模块采用面向对象的实现方式,将每个线程封装为独立对象,因此相比 <_thread> 模块,它能为线程操作提供更强大、更高级的支持。该模块从 Python 2.4 版本开始内置在 Python 中。

<threading> 模块的额外方法

<threading> 模块包含了 <_thread> 模块的所有方法,同时扩展了更多实用方法,新增方法如下:

  • threading.activeCount():返回当前处于活动状态的线程对象数量
  • threading.currentThread():返回调用者线程控制中的线程对象
  • threading.enumerate():返回当前所有活动线程对象组成的列表

为了实现线程操作,<threading> 模块提供了Thread 核心类,该类包含以下常用方法:

  • run():线程的执行入口方法
  • start():启动线程,底层会调用 run () 方法
  • join([time]):阻塞当前线程,等待目标线程执行终止(可选参数 time 为超时时间)
  • isAlive():判断线程是否仍在执行
  • getName():返回线程的名称
  • setName():设置线程的名称

如何通过 <threading> 模块创建线程?

通过 <threading> 模块创建新线程可遵循以下步骤:

  1. 定义 Thread 类的新子类;
  2. 若需要传入额外参数,重写 init(self [,args]) 构造方法;
  3. 重写 run(self [,args]) 方法,实现线程启动后需要执行的业务逻辑。

创建好 Thread 子类后,即可实例化该类,调用start() 方法启动新线程,该方法会自动调用重写后的 run() 方法。

示例

以下示例演示如何通过 <threading> 模块创建并运行新线程:

import threading
import time

exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
   def run(self):
      print ("Starting " + self.name)
      print_time(self.name, self.counter, 5)
      print ("Exiting " + self.name)

def print_time(threadName, delay, counter):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1

# 创建线程实例
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 启动线程
thread1.start()
thread2.start()

# 等待线程执行完毕
thread1.join()
thread2.join()
print ("Exiting Main Thread")

输出结果

plaintext

Starting Thread-1
Starting Thread-2
Thread-1: Mon Apr 23 10:52:09 2018
Thread-1: Mon Apr 23 10:52:10 2018
Thread-2: Mon Apr 23 10:52:10 2018
Thread-1: Mon Apr 23 10:52:11 2018
Thread-1: Mon Apr 23 10:52:12 2018
Thread-2: Mon Apr 23 10:52:12 2018
Thread-1: Mon Apr 23 10:52:13 2018
Exiting Thread-1
Thread-2: Mon Apr 23 10:52:14 2018
Thread-2: Mon Apr 23 10:52:16 2018
Thread-2: Mon Apr 23 10:52:18 2018
Exiting Thread-2
Exiting Main Thread

演示线程各状态的 Python 程序

线程共有五种状态:新建、就绪、运行、等待、终止。本节将重点演示其中三种核心状态:运行、等待、终止。线程在运行状态获取并占用系统资源,在等待状态释放资源并等待调度,执行完成后进入终止状态,最终释放所有占用的资源。

以下 Python 程序将通过 start()sleep()join() 方法,分别演示线程进入运行、等待、终止状态的过程:

步骤 1:导入所需模块 threading 和 time

import threading
import time

步骤 2:定义线程执行的目标函数

def thread_states():
   print("Thread entered in running state")

步骤 3:通过 time 模块的 sleep () 方法,让线程等待 2 秒

time.sleep(2)

步骤 4:创建线程实例 T1,指定执行的目标函数

T1 = threading.Thread(target=thread_states)

步骤 5:调用 start () 方法启动线程,控制台将打印预设的运行状态提示

T1.start()
# 输出:Thread entered in running state

步骤 6:线程执行完毕后,调用 join () 方法回收线程资源(终止线程)

T1.join()

Python 中启动线程的简易方式

Python 中有多种启动线程的方式,其中最简便的是将线程逻辑定义为单个函数,再将该函数作为目标,创建 threading.Thread 对象即可。执行以下代码,理解该方式的实现逻辑:

import threading
import time
import random

def Thread_execution(i):
   print("Execution of Thread {} started\n".format(i))
   sleepTime = random.randint(1,4)
   time.sleep(sleepTime)
   print("Execution of Thread {} finished".format(i))

# 循环创建4个线程
for i in range(4):
   thread = threading.Thread(target=Thread_execution, args=(i,))
   thread.start()
   print("Active Threads:", threading.enumerate())

输出结果

plaintext

Execution of Thread 0 started

Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>]
Execution of Thread 1 started

Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>]
Execution of Thread 2 started

Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>]
Execution of Thread 3 started

Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>,
      <Thread(Thread-3579, started 4520)>]
Execution of Thread 0 finished
Execution of Thread 1 finished
Execution of Thread 2 finished
Execution of Thread 3 finished

Python 中的守护线程

在实现守护线程前,需先了解守护线程的概念及使用场景。在计算机领域,守护线程是运行在后台的线程,主要处理数据发送、文件传输等辅助性服务请求,当无任务需要处理时会处于休眠状态。

普通的非守护线程也能实现后台任务,但主线程需要手动跟踪其状态;而守护线程无需主线程管理,当主线程退出时,所有守护线程会被自动终止

注意:守护线程仅适用于非核心任务—— 这类任务即使执行中断、未完成,也不会对程序的核心逻辑产生影响。

以下是 Python 中守护线程的实现代码:

import threading
import time

def nondaemonThread():
   print("starting my thread")
   time.sleep(8)
   print("ending my thread")

def daemonThread():
   while True:
      print("Hello")
      time.sleep(2)

if __name__ == '__main__':
   nondaemonThread = threading.Thread(target = nondaemonThread)
   daemonThread = threading.Thread(target = daemonThread)
   # 将线程设置为守护线程
   daemonThread.setDaemon(True)
   # 启动线程
   daemonThread.start()
   nondaemonThread.start()

上述代码中定义了两个函数:nondaemonThread() 为非守护线程的执行逻辑,打印状态后休眠 8 秒再结束;daemonThread() 为守护线程的执行逻辑,无限循环每 2 秒打印一次Hello

通过以下输出,可清晰看出守护线程与非守护线程的执行差异:

plaintext

Hello
starting my thread
Hello
Hello
Hello
Hello
ending my thread
Hello
Hello
Hello
Hello
Hello
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐