您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

如何通过Python线程池实现异步编程?

时间:2023-05-11 13:35:37  来源:今日头条  作者:你的老师父


线程池的概念和基本原理

线程池是一种并发处理机制,它可以在程序启动时创建一组线程,并将它们置于等待任务的状态。当任务到达时,线程池中的某个线程会被唤醒并执行任务,执行完任务后线程会返回线程池,等待下一个任务的到来。这种机制可以减少线程的创建和销毁,提高程序的性能和效率。

线程池的基本原理是将任务和线程分离,将任务提交给线程池,由线程池来管理和执行任务。线程池中的线程可以被重复利用,减少了创建和销毁线程的开销,提高了程序的性能和效率。

Python/ target=_blank class=infotextkey>Python 中线程池的实现方式

在 Python 中,线程池可以通过 concurrent.futures 模块中的 ThreadPoolExecutor 类来实现。这个类提供了一些方法来创建和管理线程池,以及提交和执行任务。

一、Python线程池的创建和销毁

  1. 创建线程池

在 Python 中,可以使用 concurrent.futures 模块中的 ThreadPoolExecutor 类来创建线程池。ThreadPoolExecutor 类的构造函数可以接受一个参数 max_workers,用于指定线程池的大小。如果不指定 max_workers,则线程池的大小会根据 CPU 的核心数来自动确定。

import concurrent.futures

def task():
    print('Task executed')

if __name__ == '__mAIn__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)

在上述代码中,创建了一个包含三个线程的线程池,并提交了一个任务。使用 with 语句可以自动关闭线程池,确保资源的正确释放。

  1. 销毁线程池

要销毁线程池,可以调用 shutdown() 方法。该方法会等待所有任务执行完毕后再关闭线程池。

import concurrent.futures

def task():
    print('Task executed')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
    executor.shutdown()

在上述代码中,关闭了线程池。

如果要立即关闭线程池,可以调用 shutdown(wait=False) 方法。该方法会立即关闭线程池,未完成的任务会被取消。这种方式需要特别小心,因为未完成的任务可能会导致程序的异常退出或数据丢失。

import concurrent.futures

def task():
    print('Task executed')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
    executor.shutdown(wait=False)

在上述代码中,立即关闭了线程池。

  1. 线程池的生命周期

线程池的生命周期包括三个阶段:

  1. 创建阶段:创建线程池,并初始化线程池中的线程。
  2. 执行阶段:接收任务并执行任务,直到所有任务执行完毕或线程池被关闭。
  3. 销毁阶段:关闭线程池,释放所有资源。

在执行阶段中,无论是任务执行成功还是失败,都需要将线程返回线程池,以便线程池继续利用。如果任务执行失败,可以使用 Future 对象的 exception() 方法获取异常信息。

import concurrent.futures

def task():
    print('Task executed')
    raise Exception('Task failed')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
        try:
            result = future.result()
        except Exception as e:
            print(f'Task failed: {e}')

在上述代码中,提交了一个会抛出异常的任务,并使用 try...except 语句来捕获异常信息。

在销毁阶段中,需要确保所有任务执行完毕后再关闭线程池。如果直接关闭线程池,未完成的任务可能会导致程序的异常退出或数据丢失。

  1. 线程池的异常处理

在使用线程池时,可能会出现各种异常,例如任务执行失败、线程池关闭失败等。为了保证程序的健壮性和可靠性,需要对这些异常进行处理。

在任务执行失败时,可以使用 Future 对象的 exception() 方法获取异常信息。在线程池关闭失败时,可以使用 ThreadPoolExecutor 类的 shutdown() 方法的返回值来判断是否成功关闭线程池。

import concurrent.futures

def task():
    print('Task executed')
    raise Exception('Task failed')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
        try:
            result = future.result()
        except Exception as e:
            print(f'Task failed: {e}')
        success = executor.shutdown(wait=False)
        if not success:
            print('Failed to shutdown thread pool')

在上述代码中,提交了一个会抛出异常的任务,并使用 try...except 语句来捕获异常信息。在关闭线程池时,使用 wait=False 参数来立即关闭线程池,并使用 shutdown() 方法的返回值来判断是否成功关闭线程池。

二、Python线程池的任务提交和执行

  1. 提交任务到线程池

要提交任务到线程池中,可以使用 submit() 方法,该方法会返回一个 Future 对象,表示任务的执行结果。

import concurrent.futures

def task():
    print('Task executed')
    return 'Task result'

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
        print(future.result())

在上述代码中,提交了一个任务,并使用 future.result() 方法获取任务的执行结果。

可以使用 map() 方法来批量提交任务,并获得所有任务的执行结果。

import concurrent.futures

def task(i):
    print(f'Task {i} executed')
    return f'Task {i} result'

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        results = executor.map(task, range(5))
        for result in results:
            print(result)

在上述代码中,使用 map() 方法批量提交任务,并获得所有任务的执行结果。

  1. 控制任务的执行顺序

在默认情况下,线程池会根据任务的提交顺序来执行任务。但是,如果需要控制任务的执行顺序,可以使用 submit() 方法的返回值 Future 对象来控制任务的执行。

import concurrent.futures

def task(i):
    print(f'Task {i} executed')
    return f'Task {i} result'

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        futures = [executor.submit(task, i) for i in range(5)]
        for future in concurrent.futures.as_completed(futures):
            result = future.result()
            print(result)

在上述代码中,使用 submit() 方法提交了多个任务,并将返回值 Future 对象保存在列表中。使用
concurrent.futures.as_completed() 函数来获取任务的执行结果,并按照完成顺序输出结果。

还可以使用 future.add_done_callback() 方法来注册回调函数,当任务执行完毕时自动调用回调函数。

import concurrent.futures

def task(i):
    print(f'Task {i} executed')
    return f'Task {i} result'

def callback(future):
    result = future.result()
    print(result)

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        futures = [executor.submit(task, i) for i in range(5)]
        for future in futures:
            future.add_done_callback(callback)

在上述代码中,使用 submit() 方法提交了多个任务,并使用 future.add_done_callback() 方法注册回调函数。当任务执行完毕时,会自动调用回调函数。

  1. 取消任务的执行

在使用线程池时,可能需要取消正在执行的任务。可以使用 Future 对象的 cancel() 方法来取消任务的执行。如果任务已经执行完毕或无法取消,cancel() 方法会返回 False。

import concurrent.futures
import time

def task():
    print('Task started')
    time.sleep(5)
    print('Task finished')
    return 'Task result'

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
        time.sleep(2)
        canceled = future.cancel()
        if canceled:
            print('Task canceled')
        else:
            print('Task not canceled')

在上述代码中,提交一个任务并等待 2 秒后取消任务的执行。如果任务已经执行完毕或无法取消,cancel() 方法会返回 False。

  1. 等待所有任务执行完毕

在使用线程池时,可能需要等待所有任务执行完毕。可以使用 wait() 方法来等待所有任务执行完毕。

import concurrent.futures

def task(i):
    print(f'Task {i} executed')
    return f'Task {i} result'

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        futures = [executor.submit(task, i) for i in range(5)]
        concurrent.futures.wait(futures)
        for future in futures:
            result = future.result()
            print(result)

在上述代码中,使用 submit() 方法提交了多个任务,并将返回值 Future 对象保存在列表中。使用 concurrent.futures.wait() 函数来等待所有任务执行完毕。

三、Python线程池的参数和配置

下面是对 Python 中线程池的参数和配置的深入讲解。

  1. 线程池的大小

线程池的大小决定了可以同时执行的任务数。在 Python 中,可以使用 max_workers 参数来配置线程池的大小。如果不指定 max_workers,线程池的大小会根据 CPU 的核心数来自动确定。

import concurrent.futures

def task():
    print('Task executed')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)

在上述代码中,创建了一个包含三个线程的线程池。如果需要更改线程池的大小,只需修改 max_workers 的值即可。

  1. 线程池的超时设置

在 Python 中,可以使用 timeout 参数来设置任务的执行超时时间。如果任务在指定的时间内没有执行完毕,线程池会自动取消任务的执行,并抛出
concurrent.futures.TimeoutError 异常。

import concurrent.futures
import time

def task():
    print('Task started')
    time.sleep(5)
    print('Task finished')
    return 'Task result'

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
        future = executor.submit(task)
        try:
            result = future.result(timeout=2)
            print(result)
        except concurrent.futures.TimeoutError:
            print('Task timeout')

在上述代码中,提交了一个需要 5 秒才能执行完毕的任务,并设置超时时间为 2 秒。因为任务没有在指定时间内执行完毕,所以会抛出
concurrent.futures.TimeoutError 异常。

  1. 线程池的任务队列

在线程池中,如果所有线程都正在执行任务,新的任务会被加入到任务队列中等待执行。在 Python 中,可以使用 queue_size 参数来配置任务队列的大小。如果任务队列已满,新的任务会被拒绝执行,并抛出
concurrent.futures.ThreadPoolExecutor 异常。

import concurrent.futures

def task():
    print('Task executed')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3, queue_size=2) as executor:
        for i in range(5):
            future = executor.submit(task)

在上述代码中,创建了一个包含三个线程和大小为 2 的任务队列的线程池。提交了 5 个任务,其中前两个任务会被立即执行,后三个任务会被加入到任务队列中等待执行。因为任务队列只能容纳 2 个任务,所以第四个任务会被拒绝执行,并抛出
concurrent.futures.ThreadPoolExecutor 异常。

  1. 线程池的线程名称和优先级

在线程池中,可以为每个线程设置名称和优先级。在 Python 中,可以使用 thread_name_prefix 和 thread_priority 参数来配置线程名称和优先级。

import concurrent.futures
import threading

def task():
    print(f'Task executed by {threading.current_thread().name}')

if __name__ == '__main__':
    with concurrent.futures.ThreadPoolExecutor(max_workers=3, thread_name_prefix='MyThread-', thread_priority=1) as executor:
        future = executor.submit(task)

在上述代码中,创建了一个包含三个线程的线程池,并为每个线程设置名称前缀为 MyThread-,优先级为 1。提交了一个任务,任务会被其中一个线程执行,并在执行时输出线程的名称。

四、线程池的应用场景

线程池适用于需要并发执行多个任务的场景,例如:

  • 网络爬虫:同时爬取多个网页。
  • 数据库操作:同时查询多个数据表。
  • 图像处理:同时处理多张图片。
  • 并发编程:同时执行多个线程。

使用线程池可以减少线程的创建和销毁,提高程序的性能和效率,同时还可以控制线程池的大小和任务的执行顺序。

总之,线程池是一个非常有用的并发处理机制,可以提高程序的性能和效率,同时也需要仔细设计和实现,以避免并发问题和线程安全问题。



Tags:Python   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Python 可视化:Plotly 库使用基础
当使用 Plotly 进行数据可视化时,我们可以通过以下示例展示多种绘图方法,每个示例都会有详细的注释和说明。1.创建折线图import plotly.graph_objects as go# 示例1: 创建简单...【详细内容】
2024-04-01  Search: Python  点击:(8)  评论:(0)  加入收藏
Python 办公神器:教你使用 Python 批量制作 PPT
介绍本文将介绍如何使用openpyxl和pptx库来批量制作PPT奖状。本文假设你已经安装了python和这两个库。本文的场景是:一名基层人员,要给一次比赛活动获奖的500名选手制作奖状,并...【详细内容】
2024-03-26  Search: Python  点击:(16)  评论:(0)  加入收藏
Python实现工厂模式、抽象工厂,单例模式
工厂模式是一种常见的设计模式,它可以帮助我们创建对象的过程更加灵活和可扩展。在Python中,我们可以使用函数和类来实现工厂模式。一、Python中实现工厂模式工厂模式是一种常...【详细内容】
2024-03-07  Search: Python  点击:(31)  评论:(0)  加入收藏
不可不学的Python技巧:字典推导式使用全攻略
Python的字典推导式是一种优雅而强大的工具,用于创建字典(dict)。这种方法不仅代码更加简洁,而且执行效率高。无论你是Python新手还是有经验的开发者,掌握字典推导式都将是你技能...【详细内容】
2024-02-22  Search: Python  点击:(32)  评论:(0)  加入收藏
如何进行Python代码的代码重构和优化?
Python是一种高级编程语言,它具有简洁、易于理解和易于维护的特点。然而,代码重构和优化对于保持代码质量和性能至关重要。什么是代码重构?代码重构是指在不改变代码外部行为的...【详细内容】
2024-02-22  Search: Python  点击:(33)  评论:(0)  加入收藏
Python开发者必备的八个PyCharm插件
在编写代码的过程中,括号几乎无处不在,以至于有时我们会拼命辨别哪个闭合括号与哪个开头的括号相匹配。这款插件能帮助解决这个众所周知的问题。前言在PyCharm中浏览插件列表...【详细内容】
2024-01-26  Search: Python  点击:(85)  评论:(0)  加入收藏
Python的Graphlib库,再也不用手敲图结构了
Python中的graphlib库是一个功能强大且易于使用的工具。graphlib提供了许多功能,可以帮助您创建、操作和分析图形对象。本文将介绍graphlib库的主要用法,并提供一些示例代码和...【详细内容】
2024-01-26  Search: Python  点击:(86)  评论:(0)  加入收藏
大语言模型插件功能在携程的Python实践
作者简介成学,携程高级安全研发工程师,关注Python/Golang后端开发、大语言模型等领域。一、背景2023年初,科技圈最火爆的话题莫过于大语言模型了,它是一种全新的聊天机器人模型,...【详细内容】
2024-01-26  Search: Python  点击:(73)  评论:(0)  加入收藏
如何使用Python、Apache Kafka和云平台构建健壮的实时数据管道
译者 | 李睿审校 | 重楼在当今竞争激烈的市场环境中,为了生存和发展,企业必须能够实时收集、处理和响应数据。无论是检测欺诈、个性化用户体验还是监控系统,现在都需要接近即时...【详细内容】
2024-01-26  Search: Python  点击:(46)  评论:(0)  加入收藏
Python分布式爬虫打造搜索引擎
简单分布式爬虫结构主从模式是指由一台主机作为控制节点负责所有运行网络爬虫的主机进行管理,爬虫只需要从控制节点那里接收任务,并把新生成任务提交给控制节点就可以了,在这个...【详细内容】
2024-01-25  Search: Python  点击:(58)  评论:(0)  加入收藏
▌简易百科推荐
Python 可视化:Plotly 库使用基础
当使用 Plotly 进行数据可视化时,我们可以通过以下示例展示多种绘图方法,每个示例都会有详细的注释和说明。1.创建折线图import plotly.graph_objects as go# 示例1: 创建简单...【详细内容】
2024-04-01  Python技术    Tags:Python   点击:(8)  评论:(0)  加入收藏
Python 办公神器:教你使用 Python 批量制作 PPT
介绍本文将介绍如何使用openpyxl和pptx库来批量制作PPT奖状。本文假设你已经安装了python和这两个库。本文的场景是:一名基层人员,要给一次比赛活动获奖的500名选手制作奖状,并...【详细内容】
2024-03-26  Python技术  微信公众号  Tags:Python   点击:(16)  评论:(0)  加入收藏
Python实现工厂模式、抽象工厂,单例模式
工厂模式是一种常见的设计模式,它可以帮助我们创建对象的过程更加灵活和可扩展。在Python中,我们可以使用函数和类来实现工厂模式。一、Python中实现工厂模式工厂模式是一种常...【详细内容】
2024-03-07  Python都知道  微信公众号  Tags:Python   点击:(31)  评论:(0)  加入收藏
不可不学的Python技巧:字典推导式使用全攻略
Python的字典推导式是一种优雅而强大的工具,用于创建字典(dict)。这种方法不仅代码更加简洁,而且执行效率高。无论你是Python新手还是有经验的开发者,掌握字典推导式都将是你技能...【详细内容】
2024-02-22  子午Python  微信公众号  Tags:Python技巧   点击:(32)  评论:(0)  加入收藏
如何进行Python代码的代码重构和优化?
Python是一种高级编程语言,它具有简洁、易于理解和易于维护的特点。然而,代码重构和优化对于保持代码质量和性能至关重要。什么是代码重构?代码重构是指在不改变代码外部行为的...【详细内容】
2024-02-22  编程技术汇    Tags:Python代码   点击:(33)  评论:(0)  加入收藏
Python开发者必备的八个PyCharm插件
在编写代码的过程中,括号几乎无处不在,以至于有时我们会拼命辨别哪个闭合括号与哪个开头的括号相匹配。这款插件能帮助解决这个众所周知的问题。前言在PyCharm中浏览插件列表...【详细内容】
2024-01-26  Python学研大本营  微信公众号  Tags:PyCharm插件   点击:(85)  评论:(0)  加入收藏
Python的Graphlib库,再也不用手敲图结构了
Python中的graphlib库是一个功能强大且易于使用的工具。graphlib提供了许多功能,可以帮助您创建、操作和分析图形对象。本文将介绍graphlib库的主要用法,并提供一些示例代码和...【详细内容】
2024-01-26  科学随想录  微信公众号  Tags:Graphlib库   点击:(86)  评论:(0)  加入收藏
Python分布式爬虫打造搜索引擎
简单分布式爬虫结构主从模式是指由一台主机作为控制节点负责所有运行网络爬虫的主机进行管理,爬虫只需要从控制节点那里接收任务,并把新生成任务提交给控制节点就可以了,在这个...【详细内容】
2024-01-25  大雷家吃饭    Tags:Python   点击:(58)  评论:(0)  加入收藏
使用Python进行数据分析,需要哪些步骤?
Python是一门动态的、面向对象的脚本语言,同时也是一门简约,通俗易懂的编程语言。Python入门简单,代码可读性强,一段好的Python代码,阅读起来像是在读一篇外语文章。Python这种特...【详细内容】
2024-01-15  程序员不二    Tags:Python   点击:(162)  评论:(0)  加入收藏
Python语言的特点及应用场景, 同其它语言对比优势
Python语言作为一种高级编程语言,具有许多独特的特点和优势,这使得它在众多编程语言中脱颖而出。在本文中,我们将探讨Python语言的特点、应用场景以及与其他语言的对比优势。一...【详细内容】
2024-01-09    今日头条  Tags:Python语言   点击:(253)  评论:(0)  加入收藏
站内最新
站内热门
站内头条