Python多线程编程实战:从基础到高级应用

七月
七月
发布时间:2026-10-16 | 12人浏览过
原创

本文详细讲解Python中多线程的使用方法及核心模块。涵盖_thread与threading模块的区别,Thread类常用方法,以及利用Lock实现线程同步解决数据竞争问题。同时深入解析Queue队列模块(Queue、LifoQueue、PriorityQueue等)的参数与实战应用,帮助开发者掌握高效并发编程技巧。

一、简介

在Python中实现多线程主要有两种途径:一是通过函数直接调用,二是将线程对象封装在类中。

函数式方法:通过调用 _thread 模块提供的 start_new_thread() 函数来创建并启动新线程。

参数说明:

  • function - 指定线程执行的函数。
  • args - 传递给线程函数的参数元组,类型必须为tuple。
  • kwargs - 可选的关键字参数字典。

实例:

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: 无法启动线程")
while 1:
   pass

二、线程模块

Python 3 提供了 _thread 和 threading 两个标准库来支持多线程功能。

_thread 模块提供了底层且原始的线程操作及简单锁机制,其功能相比 threading 模块较为有限。

threading 模块不仅包含 _thread 模块的所有方法,还额外提供了以下高级方法:

  • threading.currentThread(): 获取当前线程变量。
  • threading.enumerate(): 返回当前正在运行的线程列表。正在运行指线程已启动且未结束,不包含已启动前或已终止后的线程。
  • threading.activeCount(): 返回当前活跃线程的数量,其结果与 len(threading.enumerate()) 相同。

除了直接使用函数,线程模块还提供了 Thread 类来处理线程,该类包含以下方法:

  • run(): 定义线程活动逻辑的方法。
  • start(): 启动线程活动。
  • join([time]): 阻塞调用线程,直到目标线程结束。线程正常退出、抛出未处理异常或发生可选超时后,join() 方法才会返回。
  • isAlive(): 检查线程是否处于活动状态。
  • getName(): 获取线程名称。
  • setName(): 设置线程名称。

三、使用 threading 模块创建线程

可以通过继承 threading.Thread 类来创建自定义子类,实例化后调用 start() 方法启动新线程,该方法内部会调用线程的 run() 方法:

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 ("开始线程:" + self.name)
        print_time(self.name, self.counter, 5)
        print ("退出线程:" + 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 ("退出主线程")

四、线程同步

当多个线程同时修改同一数据时,可能导致结果不可预测。为确保数据正确性,需要对多线程操作进行同步控制。

使用 Thread 对象的 Lock 和 Rlock 可实现简单的线程同步。这两个对象均提供 acquire 和 release 方法,对于每次仅允许一个线程操作的数据,可将相关操作置于 acquire 和 release 之间执行。

如下:

注意: 多线程的优势在于能够同时执行多个任务(至少在感知上如此)。然而,当线程共享数据时,可能出现数据不同步的问题。

考虑以下场景:一个列表初始元素全为0,线程"set"从后向前将所有元素修改为1,而线程"print"负责从前向后读取并打印列表。若线程"set"开始修改时线程"print"开始打印,输出结果可能是一半0一半1,即数据不同步。为解决此问题,引入锁机制。锁具有两种状态:锁定和未锁定。当线程(如"set")访问共享数据前,必须先获取锁;若其他线程(如"print")已持有锁,则当前线程进入同步阻塞状态;待持有锁的线程访问完毕并释放锁后,当前线程方可继续执行。经此处理,打印列表时要么全为0,要么全为1,避免了混合输出的情况。

实例:

import threading
import time
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 ("开启线程: " + self.name)
        # 获取锁,用于线程同步
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁,开启下一个线程
        threadLock.release()
def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1
threadLock = threading.Lock()
threads = []
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有线程完成
for t in threads:
    t.join()
print ("退出主线程")

五、线程优先级队列( Queue)

1、queue队列

(1. Python 3中的队列模块名为queue,而非Queue。

(2. 通常涉及同步或多线程场景时会用到队列模块。

(3. 定义了 queue.Queue 类,以及继承自它的 queue.LifoQueue 类、queue.PriorityQueue 类和 queue.SimpleQueue 类。

(4. 分别对应先进先出(FIFO)队列、后进先出(LIFO)队列、优先队列以及无边界FIFO简单队列。

(5. 还包含两个异常类型:队满和队空。

2、队列queue公共方法

'''
学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
import queue
#创建基本队列
#queue.Queue(maxsize=0)创建一个队列对象(队列容量),若maxsize小于或者等于0,队列大小没有限制
Q=queue.Queue(10)
print(Q)
print(type(Q))
#1.基本方法
print(Q.queue)#查看队列中所有元素
print(Q.qsize())#返回队列的大小
print(Q.empty())#判断队空
print(Q.full())#判断队满
#2.获取队列,0--5
#Queue.put(item,block = True,timeout = None )将对象放入队列,阻塞调用(block=False抛异常),无等待时间
for i in range(5):
    Q.put(i)
# Queue.put_nowait(item)相当于 put(item, False).
#3.读队列,0--5
#Queue.get(block=True, timeout=None)读出队列的一个元素,阻塞调用,无等待时间
while not Q.empty():
    print(Q.get())
# Queue.get_nowait()相当于get(False).取数据,如果没数据抛queue.Empty异常
#4.另两种涉及等待排队任务的方法
# Queue.task_done()在完成一项工作后,向任务已经完成的队列发送一个信号
# Queue.join()阻止直到队列中的所有项目都被获取并处理。即等到队列为空再执行别的操作

3、其他

(1. LifoQueue:后进先出队列。

(2. PriorityQueue:优先级队列。若数据元素不可比,可将数据包装在忽略数据项的类中,仅比较优先级编号。

(3. SimpleQueue:简单队列,无跟踪任务的功能。

六、Queue详细参数和用法实例

Queue 模块中的常用方法:

  • Queue.qsize() 返回队列中元素的数量。
  • Queue.empty() 若队列为空返回True,否则返回False。
  • Queue.full() 若队列已满返回True,否则返回False。
  • Queue.full 的状态与 maxsize 参数大小对应。
  • Queue.get([block[, timeout]]) 获取队列元素,block控制是否阻塞,timeout指定等待时间。
  • Queue.get_nowait() 等效于 Queue.get(False)。
  • Queue.put(item) 写入队列元素,block控制是否阻塞,timeout指定等待时间。
  • Queue.put_nowait(item) 等效于 Queue.put(item, False)。
  • Queue.task_done() 在完成一项工作后,向任务队列发送一个完成信号。
  • Queue.join() 阻塞直到队列为空,之后才执行其他操作。

实例:

import queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
    def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print ("开启线程:" + self.name)
        process_data(self.name, self.q)
        print ("退出线程:" + self.name)
def process_data(threadName, q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print ("%s processing %s" % (threadName, data))
        else:
            queueLock.release()
        time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1
# 创建新线程
for tName in threadList:
    thread = myThread(threadID, tName, workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1
# 填充队列
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()
# 等待队列清空
while not workQueue.empty():
    pass
# 通知线程是时候退出
exitFlag = 1
# 等待所有线程完成
for t in threads:
    t.join()
print ("退出主线程")

到此这篇关于Python多线程使用方法详细讲解的文章就介绍到这了,更多相关Python多线程内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表