极简concurrent库

Python的concurrent库包含futures模块,这是一个高级接口,用于异步执行调用。concurrent.futures模块提供了ThreadPoolExecutorProcessPoolExecutor两个类,分别用于线程池和进程池的异步执行。

concurrent库架构

concurrent.futures模块的基础架构可以分为两个主要部分:

  1. Executor:这是异步执行调用的基础。有两种主要的Executor:
    • ThreadPoolExecutor:使用线程池来异步执行调用。
    • ProcessPoolExecutor:使用进程池来异步执行调用。
  2. Future:这是异步执行调用的结果对象。通过Future对象,你可以查看异步执行的状态、获取结果或者取消执行。

基本语法

下面是使用ThreadPoolExecutorProcessPoolExecutor的基本语法:

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
# 使用线程池
with ThreadPoolExecutor(max_workers=5) as executor:
    future = executor.submit(function, argument)
# 使用进程池
with ProcessPoolExecutor(max_workers=5) as executor:
    future = executor.submit(function, argument)

在上面的代码中,max_workers参数指定了线程或进程的最大数量,function是你要异步执行的方法,argument是这个方法的参数。

内容:详细讲解

下面我们将通过一个简单的例子来详细讲解如何使用ThreadPoolExecutor

简单示例

假设我们有一个简单的函数,用于计算一个数的平方:

def square(num):
    return num * num

我们可以使用ThreadPoolExecutor来异步执行这个函数:

from concurrent.futures import ThreadPoolExecutor
# 使用线程池异步计算平方
with ThreadPoolExecutor(max_workers=5) as executor:
    numbers = [1, 2, 3, 4, 5]
    results = [executor.submit(square, num) for num in numbers]
# 获取异步计算的结果
for future in results:
    print(future.result())

在这个例子中,我们首先创建了一个ThreadPoolExecutor对象,然后使用列表推导式提交了5个任务到线程池中。最后,我们遍历results列表,调用future.result()来获取每个异步执行的结果。
注意:在实际的多线程环境中,由于GIL(Global Interpreter Lock)的存在,Python的多线程可能不会带来性能上的提升,特别是在CPU密集型的任务中。在这种情况下,使用ProcessPoolExecutor可能会更加合适。

以下是执行代码的结果:

1 4 9 16 25

这个结果展示了我们通过ThreadPoolExecutor异步计算平方数的过程。每个数字都被正确地计算了其平方,并返回了相应的结果。

异步执行与回调

concurrent.futures允许你为每个Future对象设置一个回调函数。这个回调函数会在Future完成执行后被自动调用。

示例:使用回调函数

from concurrent.futures import ThreadPoolExecutor
# 定义一个简单的平方函数
def square(num):
    return num * num
# 定义一个回调函数,用于打印结果
def print_result(future):
    print(future.result())
# 使用线程池异步计算平方,并设置回调函数
with ThreadPoolExecutor(max_workers=5) as executor:
    numbers = [1, 2, 3, 4, 5]
    for num in numbers:
        future = executor.submit(square, num)
        future.add_done_callback(print_result)

以下是执行代码的结果:

1 4 9 16 25

在这个例子中,我们为每个Future对象添加了一个print_result回调函数。这意味着当每个Future完成执行后,其结果将被自动打印出来。

Map函数

Executor类还提供了一个map函数,它类似于内置的map函数,但可以异步执行。

示例:使用map函数

from concurrent.futures import ThreadPoolExecutor
# 定义一个简单的平方函数
def square(num):
    return num * num
# 使用线程池的map函数异步计算平方
with ThreadPoolExecutor(max_workers=5) as executor:
    numbers = [1, 2, 3, 4, 5]
    results = executor.map(square, numbers)
# 输出结果
for result in results:
    print(result)

以下是执行代码的结果:

1 4 9 16 25

在这个例子中,我们使用了executor.map函数来异步计算平方。executor.map函数会返回一个迭代器,我们可以遍历它来获取结果。

异常处理

在异步执行中,异常处理是一个重要的方面。如果异步执行的函数抛出了异常,你可以通过Future对象的exception方法来捕获它。

示例:异常处理

from concurrent.futures import ThreadPoolExecutor
import math
# 定义一个可能导致异常的函数
def unsafe_function(num):
    if num == 0:
        raise ValueError("Cannot divide by zero")
    return 10 / num
# 使用线程池异步执行可能导致异常的函数,并进行异常处理
with ThreadPoolExecutor(max_workers=5) as executor:
    numbers = [1, 2, 0, 3, 4, 5]
    futures = [executor.submit(unsafe_function, num) for num in numbers]
    for future in futures:
        try:
            print(future.result())
        except ValueError as e:
            print(f"Error: {e}")

在这个例子中,我们定义了一个可能会抛出ValueError异常的函数unsafe_function。我们通过future.result()获取结果,并在异常捕获块中处理可能的异常。
以下是执行异常处理示例代码的结果:

10.0
5.0
Error: Cannot divide by zero
3.3333333333333335
2.5
2.0

这个结果展示了我们如何使用concurrent.futures进行异常处理。当尝试除以0时,我们捕获了ValueError异常,并打印了相应的错误信息。其他数字成功计算了结果。

Future对象的状态

Future对象有几个属性可以用来检查其状态:

  • done():如果调用完成,返回True
  • running():如果正在运行,返回True
  • cancelled():如果调用被取消,返回True

示例:检查Future状态

from concurrent.futures import ThreadPoolExecutor, TimeoutError
# 定义一个简单的平方函数
def square(num):
    import time
    time.sleep(4)
    return num * num


# 使用线程池异步计算平方
with ThreadPoolExecutor(max_workers=5) as executor:
    future = executor.submit(square, 4)

    # 检查Future的状态
    print(f"Future done: {future.done()}")
    print(f"Future running: {future.running()}")
    print(f"Future cancelled: {future.cancelled()}")

    # 等待结果,这里由于任务很快完成,所以不会超时
    try:
        result = future.result(timeout=6)
        print(f"Result: {result}")
    except TimeoutError:
        print("Timeout occurred")

在这个例子中,我们提交了一个异步的平方计算任务,并检查了Future对象的不同状态。由于任务是快速完成的,我们能够获取到结果,而不会触发超时。
现在,我将执行上述的Future状态检查示例代码,以展示其运行结果。
以下是执行Future状态检查示例代码的结果:

Future done: False
Future running: True
Future cancelled: False
Result: 16

这个结果展示了Future对象的不同状态:

  • Future done:最初,因为任务还在运行,所以返回False
  • Future running:由于任务正在执行,返回True
  • Future cancelled:任务没有被取消,所以返回False
  • Result:最终,我们成功获取了异步计算的结果,即4的平方,等于16。

等待多个任务完成

concurrent.futures库提供了一个as_completed()函数,它可以用来迭代那些已经完成的Future对象,而不需要等待所有Future对象都完成。

示例:使用as_completed()

from concurrent.futures import ThreadPoolExecutor, as_completed
# 定义一个简单的平方函数
def square(num):
    return num * num
# 使用线程池异步计算平方
with ThreadPoolExecutor(max_workers=5) as executor:
    futures = {executor.submit(square, i): i for i in range(1, 6)}
    
    # 使用as_completed迭代已完成的Future
    for future in as_completed(futures):
        index = futures[future]
        try:
            result = future.result()
            print(f"Index {index}: {result}")
        except Exception as exc:
            print(f"Index {index} generated an exception: {exc}")

在这个例子中,我们提交了一系列的异步平方计算任务,并使用as_completed()来迭代那些已经完成的Future对象。这样可以立即处理每个完成的任务,而不需要等待其他任务。

超时设置

有时,你可能希望为Future对象的result()方法设置一个超时。如果Future在指定的时间内没有完成,则会抛出一个TimeoutError异常。

示例:设置超时

from concurrent.futures import ThreadPoolExecutor, TimeoutError
# 定义一个简单的平方函数
def square(num):
    import time
    time.sleep(4)
    return num * num
# 使用线程池异步计算平方
with ThreadPoolExecutor(max_workers=5) as executor:
    future = executor.submit(square, 4)
    
    # 尝试获取结果,但设置一个较短的超时时间
    try:
        result = future.result(timeout=0.001)
        print(f"Result: {result}")
    except TimeoutError:
        print("Timeout occurred")

在这个例子中,我们提交了一个异步的平方计算任务,并为result()方法设置了一个非常短的超时时间。由于任务无法在这个时间内完成,所以会触发TimeoutError异常。
以下是执行示例代码的结果:

Timeout occurred

这个结果展示了我们如何使用as_completed()函数来迭代那些已经完成的Future对象。每个任务完成后,我们立即处理其结果,而不需要等待其他任务完成。注意,由于任务是并行执行的,所以结果的顺序可能与提交的顺序不同。

总结

希望这些内容能够帮助你更好地理解和使用Python的concurrent.futures库。

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉小雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值