`concurrent.futures` 是 Python 标准库中的一个模块
先来看文档
concurrent.futures
是 Python 标准库中的一个模块,它提供了一个高级接口来异步执行代码,使用线程或进程池来并行运行任务。这个模块提供了两种主要的池类型:ThreadPoolExecutor
和 ProcessPoolExecutor
,以及一个通用的 Executor
接口。此外,Executor
接口中的 submit
方法用于提交任务给执行器执行。
1. ThreadingPoolExecutor
ThreadPoolExecutor
使用线程池来并行执行任务。由于线程共享同一个进程的内存空间,因此线程间通信和共享数据相对容易,但这也意味着它们不能充分利用多核处理器的优势,因为 Python 的全局解释器锁(GIL)限制了同一时间只有一个线程可以执行 Python 字节码。
2. ProcessPoolExecutor
ProcessPoolExecutor
使用进程池来并行执行任务。每个进程都有自己独立的内存空间,因此它们可以绕过 GIL,充分利用多核处理器的优势。然而,进程间通信和共享数据比线程间要复杂和昂贵。
3. Executor.submit
submit
方法是 Executor
接口的一部分,用于提交一个可调用的对象(通常是函数)给执行器执行。它返回一个 Future
对象,这个对象可以用来查询任务的状态、获取任务的返回值或取消任务。
示例
使用 ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor
import timedef task(n):time.sleep(2)return n * nwith ThreadPoolExecutor(max_workers=3) as executor:futures = [executor.submit(task, i) for i in range(10)]for future in futures:print(future.result())
在这个例子中,我们创建了一个 ThreadPoolExecutor
,其最大工作线程数为 3。然后,我们提交了 10 个任务给执行器,每个任务调用 task
函数,并等待每个任务完成,打印其返回值。
使用 ProcessPoolExecutor
from concurrent.futures import ProcessPoolExecutor
import osdef task(n):return os.getpid(), n * nwith ProcessPoolExecutor(max_workers=3) as executor:futures = [executor.submit(task, i) for i in range(10)]for future in futures:pid, result = future.result()print(f"PID: {pid}, Result: {result}")
在这个例子中,我们创建了一个 ProcessPoolExecutor
,其最大工作进程数为 3。每个任务调用 task
函数,返回当前进程的 PID 和 n * n
的结果。我们打印每个任务的进程 ID 和结果,以展示任务是在不同的进程中执行的。
总结
ThreadPoolExecutor
适用于 I/O 密集型任务,因为线程间通信成本低。ProcessPoolExecutor
适用于 CPU 密集型任务,因为它可以绕过 GIL,充分利用多核处理器。submit
方法用于提交任务给执行器,并返回一个Future
对象用于查询任务状态或获取结果。
在 concurrent.futures
模块中,submit
函数是 Executor
接口的一部分,用于提交一个可调用的对象(如函数)给执行器(如 ThreadPoolExecutor
或 ProcessPoolExecutor
)异步执行。以下是对 submit
函数参数的详细说明,以及为何 name=value
时是实参,而 **kwargs
是形参的解释。
submit 函数的参数
submit
函数的定义通常如下:
submit(fn, *args, **kwargs)
fn
:这是需要异步执行的函数。它应该是一个可调用的对象,如函数、方法或实现了__call__
方法的类的实例。*args
:这是传递给fn
函数的位置参数。*args
允许你传递任意数量的位置参数给fn
。**kwargs
:这是传递给fn
函数的关键字参数。**kwargs
允许你传递任意数量的关键字参数给fn
,这些参数在函数调用时以name=value
的形式传递。
实参(Actual Arguments)与形参(Formal Parameters)
-
实参:在函数调用时传递给函数的实际值。在
submit
函数的上下文中,当你使用name=value
的形式传递参数时,这些name=value
对就是实参。例如,在executor.submit(my_function, x=10, y=20)
中,x=10
和y=20
就是实参。 -
形参:在函数定义中声明的参数。在
submit
函数被调用的函数fn
的上下文中,fn
函数定义中声明的参数就是形参。例如,如果fn
定义为def my_function(x, y)
,则x
和y
就是形参。
当你使用 **kwargs
在 submit
函数中传递参数时,这些参数以关键字参数的形式传递给 fn
函数。由于 **kwargs
在 submit
函数定义中是一个形参(它接受任意数量的关键字参数),而这些关键字参数在 submit
被调用时成为传递给 fn
函数的实参。
示例
假设我们有一个简单的函数 my_function
,它接受两个参数 x
和 y
,并返回它们的和:
def my_function(x, y):return x + y
我们可以使用 ThreadPoolExecutor
和 submit
函数来异步调用 my_function
:
from concurrent.futures import ThreadPoolExecutorwith ThreadPoolExecutor(max_workers=1) as executor:future = executor.submit(my_function, x=10, y=20) # 这里 x=10, y=20 是实参result = future.result() # 获取异步执行的结果print(result) # 输出: 30
在这个例子中,x=10
和 y=20
是传递给 my_function
的实参,而 x
和 y
是 my_function
的形参。**kwargs
在 submit
函数中允许我们以关键字参数的形式传递这些实参给 my_function
。