Python3入门指南Python语言的特点和实际应用Python3环境搭建配置VSCode进行Python开发Python基础语法Python变量与数据类型Python数据类型转换Python解释器使用Python注释使用Python运算符Python数字类型Python字符串操作Python列表操作Python元组使用Python字典使用Python集合使用Python条件控制详解Python循环语句详解Python编程入门实践Python推导式详解Python迭代器和生成器Python with语句详解Python函数详解Python lambda(匿名函数)Python装饰器Python数据结构Python模块和包使用Python中__name__和__main__的用法Python输入输出:从基础到文件操作Python文件操作Python OS模块使用Python错误和异常处理Python面向对象编程Python命名空间和作用域Python虚拟环境:venv详细教程Python类型注解Python标准库常用模块Python正则表达式Python CGI编程Python MySQL(mysql-connector驱动)Python MySQL(PyMySQL驱动)Python网络编程Python发送邮件Python多线程编程Python XML解析Python JSON解析Python日期和时间处理Python操作MongoDBPython urllib库使用Python uWSGI 安装与配置Python pip包管理工具Python operator模块Python math模块Python requests模块HTTP请求Python random模块Python OpenAI库Python AI绘画制作Python statistics模块Python hashlib模块:哈希加密Python量化交易Python pyecharts数据可视化Python Selenium网页自动化Python BeautifulSoup网页数据提取Python Scrapy爬虫框架Python Markdown转HTMLPython sys模块Python Pickle模块:数据存储Python subprocess模块Python queue队列模块Python StringIO内存文件操作Python logging日志记录Python datetime日期时间处理Python re正则表达式Python csv表格数据处理Python threading 多线程编程Python asyncio 异步编程Python PyQt 图形界面开发Python 应用方向和常用库框架

Python多线程编程

在编程中,多线程是一个很有用的技术。它让程序能够同时处理多个任务,就像一个人可以一边听音乐一边打字。Python3提供了多线程编程的支持,让我们能够编写出更有效率的程序。


多线程是什么?

多线程就像在一个程序中同时运行多个小任务。每个小任务称为一个线程,它们共享程序的资源,但各自独立运行。

多线程的好处:

  • 可以把耗时的任务放到后台执行,不会让程序卡住

  • 让用户界面更友好,比如在执行任务时显示进度条

  • 在某些情况下加快程序运行速度

  • 在处理等待任务时特别有用,比如等待用户输入、读写文件或网络传输


Python中的线程模块

Python3有两个线程模块:_thread和threading。_thread是比较基础的模块,功能有限。threading模块功能更丰富,是我们通常使用的选择。

使用_thread模块

这是基础的多线程实现方式:

import _thread
import time

def print_time(thread_name, delay):
    count = 0
    while count < 3:
        time.sleep(delay)
        count += 1
        print(f"{thread_name}: {time.ctime(time.time())}")

try:
    _thread.start_new_thread(print_time, ("线程-1", 2))
    _thread.start_new_thread(print_time, ("线程-2", 3))
except:
    print("启动线程出错")

# 保持程序运行
time.sleep(10)

这个例子创建了两个线程,每个线程都会打印三次当前时间。由于线程是同时运行的,你会看到它们的输出交错出现。

使用threading模块

threading模块提供了更好的线程控制功能:

import threading
import time

def print_numbers():
    for i in range(3):
        time.sleep(1)
        print(f"数字: {i}")

def print_letters():
    for letter in ['A', 'B', 'C']:
        time.sleep(1.5)
        print(f"字母: {letter}")

# 创建线程
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)

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

# 等待线程结束
thread1.join()
thread2.join()

print("所有线程执行完毕")


用类的方式创建线程

除了使用函数,我们还可以通过继承Thread类来创建线程:

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name, delay):
        threading.Thread.__init__(self)
        self.name = name
        self.delay = delay
        
    def run(self):
        print(f"线程 {self.name} 开始")
        self.print_time()
        print(f"线程 {self.name} 结束")
        
    def print_time(self):
        count = 0
        while count < 3:
            time.sleep(self.delay)
            count += 1
            print(f"{self.name}: {time.ctime(time.time())}")

# 创建并启动线程
thread1 = MyThread("线程一", 1)
thread2 = MyThread("线程二", 2)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print("主线程结束")


线程同步

当多个线程需要访问同一个数据时,可能会出现问题。比如一个线程在读取数据,另一个线程在修改数据,这时读取到的数据可能不正确。

为了解决这个问题,我们需要使用锁(Lock):

import threading
import time

class BankAccount:
    def __init__(self):
        self.balance = 100  # 初始余额
        self.lock = threading.Lock()
    
    def withdraw(self, amount):
        with self.lock:  # 自动获取和释放锁
            print(f"当前余额: {self.balance}")
            if amount <= self.balance:
                time.sleep(0.1)  # 模拟处理时间
                self.balance -= amount
                print(f"取款 {amount} 成功,余额: {self.balance}")
                return True
            else:
                print(f"取款 {amount} 失败,余额不足")
                return False

def customer_operation(account, amount, operations):
    for i in range(operations):
        account.withdraw(amount)

# 创建银行账户
account = BankAccount()

# 创建多个线程模拟多个客户
threads = []
for i in range(3):
    thread = threading.Thread(target=customer_operation, 
                             args=(account, 20, 2))
    threads.append(thread)
    thread.start()

# 等待所有线程完成
for thread in threads:
    thread.join()

print(f"最终余额: {account.balance}")

如果不使用锁,多个线程同时修改余额,可能会导致余额计算错误。使用锁可以保证同一时间只有一个线程能修改数据。


线程队列

在实际应用中,我们经常使用队列来管理线程任务。队列是线程安全的,适合在多线程环境中使用。

import threading
import queue
import time

# 创建队列和工作锁
work_queue = queue.Queue()
queue_lock = threading.Lock()

class WorkerThread(threading.Thread):
    def __init__(self, name, queue):
        threading.Thread.__init__(self)
        self.name = name
        self.queue = queue
        
    def run(self):
        print(f"{self.name} 开始工作")
        while True:
            try:
                # 从队列获取任务,等待2秒
                task = self.queue.get(timeout=2)
                print(f"{self.name} 正在处理: {task}")
                time.sleep(1)  # 模拟处理时间
                print(f"{self.name} 完成: {task}")
                self.queue.task_done()
            except queue.Empty:
                print(f"{self.name} 没有任务,结束工作")
                break

# 创建任务列表
tasks = [f"任务{i}" for i in range(1, 11)]

# 将任务放入队列
for task in tasks:
    work_queue.put(task)

# 创建工作者线程
workers = []
for i in range(3):  # 创建3个工作线程
    worker = WorkerThread(f"工作者-{i+1}", work_queue)
    worker.start()
    workers.append(worker)

# 等待所有任务完成
work_queue.join()

print("所有任务完成")


实际应用场景

场景一:下载多个文件

import threading
import time
import random

def download_file(filename, size):
    print(f"开始下载 {filename}")
    download_time = random.uniform(1, 3)  # 模拟下载时间
    time.sleep(download_time)
    print(f"完成下载 {filename},大小: {size}MB,用时: {download_time:.2f}秒")

files = [
    ("file1.zip", 10),
    ("file2.pdf", 5),
    ("file3.jpg", 2),
    ("file4.mp4", 50)
]

threads = []
for filename, size in files:
    thread = threading.Thread(target=download_file, args=(filename, size))
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()

print("所有文件下载完成")

场景二:数据处理管道

import threading
import queue
import time

class DataProcessor:
    def __init__(self):
        self.raw_data_queue = queue.Queue()
        self.processed_data_queue = queue.Queue()
        
    def data_collector(self, data_list):
        for data in data_list:
            print(f"收集数据: {data}")
            self.raw_data_queue.put(data)
            time.sleep(0.5)
        
    def data_processor(self):
        while True:
            try:
                raw_data = self.raw_data_queue.get(timeout=3)
                processed_data = f"处理后的{raw_data}"
                print(f"处理数据: {raw_data} -> {processed_data}")
                self.processed_data_queue.put(processed_data)
                self.raw_data_queue.task_done()
                time.sleep(1)
            except queue.Empty:
                break
                
    def data_saver(self):
        saved_count = 0
        while True:
            try:
                processed_data = self.processed_data_queue.get(timeout=3)
                print(f"保存数据: {processed_data}")
                saved_count += 1
                self.processed_data_queue.task_done()
                time.sleep(0.5)
            except queue.Empty:
                break
        print(f"总共保存了 {saved_count} 条数据")

# 使用数据处理管道
processor = DataProcessor()

# 模拟数据
sample_data = [f"数据{i}" for i in range(1, 6)]

# 创建并启动线程
collector_thread = threading.Thread(target=processor.data_collector, 
                                  args=(sample_data,))
processor_thread = threading.Thread(target=processor.data_processor)
saver_thread = threading.Thread(target=processor.data_saver)

collector_thread.start()
processor_thread.start()
saver_thread.start()

# 等待所有任务完成
collector_thread.join()
processor.raw_data_queue.join()
processor.processed_data_queue.join()

print("数据处理完成")


注意事项

  1. 全局解释器锁(GIL):Python的GIL限制同一时间只能有一个线程执行Python字节码,所以多线程在CPU密集型任务中可能不会提高速度。

  2. 线程安全:多个线程修改共享数据时一定要使用锁或其他同步机制。

  3. 避免死锁:不要在持有锁的情况下等待另一个锁,这可能导致程序卡住。

  4. 合理使用线程数量:创建太多线程会消耗系统资源,反而降低性能。


总结

多线程是Python编程中的重要技术,适合处理I/O密集型任务。通过threading模块,我们可以轻松创建和管理线程。记住要处理好线程同步问题,合理使用锁和队列。在实际项目中,多线程可以显著提高程序的响应速度和处理能力。

对于想深入学习的朋友,建议在fly63教程网站上查看更详细的多线程教程和实例。多练习实际项目,才能更好地掌握多线程编程技巧。

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/course/36_2115

目录选择