Python使用future处理并发问题方案详解

  • Post category:Python

Python 使用future处理并发问题方案详解

在Python中,处理并发问题有多种方法,其中较为常用的是使用future模块。本文将对future模块的使用进行详细讲解,包括其基本用法、示例说明等。

什么是future

future是Python标准库中的一个模块,用于在多线程/多进程编程中处理异步计算任务。它提供了一些类,如FutureThreadPoolExecutorProcessPoolExecutor等,方便用户进行异步计算任务和并发编程。

Futurefuture模块的核心类。它通过异步方式执行和管理计算任务,并在任务完成后返回结果。ThreadPoolExecutorProcessPoolExecutor都是通过多线程/多进程方式创建一个池子,方便管理异步任务。

future模块基本用法

Future类

Future 类表示一个异步计算任务,它的主要作用是通过异步管理任务,并在任务完成后返回结果。

from concurrent.futures import Future

# 创建一个Future对象
future = Future()

Future 类提供了以下方法来管理异步任务:

  • add_done_callback(fn):添加任务完成时的回调方法fn
  • done():判断任务是否完成,如果完成返回True,否则返回False
  • result(timeout=None):获取任务的结果,如果任务未完成会一直等待,如果在指定的timeout时间内没有获得结果,则触发TimeoutError异常。
  • exception(timeout=None):获取任务的异常,如果任务未出现异常则返回None

ThreadPoolExecutor类和ProcessPoolExecutor类

ThreadPoolExecutor 类和 ProcessPoolExecutor 类都是通过多线程/多进程方式创建一个池子,以方便管理异步任务。

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# 创建一个线程池
with ThreadPoolExecutor() as executor:
    # 添加异步任务
    future = executor.submit(func, *args, **kwargs)

# 创建一个进程池
with ProcessPoolExecutor() as executor:
    # 添加异步任务
    future = executor.submit(func, *args, **kwargs)

ThreadPoolExecutorProcessPoolExecutor 都支持以下方法:

  • submit(fn, *args, **kwargs):用于将fn(*args, **kwargs)提交到池子中,并返回一个Future对象,表示异步任务。
  • shutdown(wait=True):用于关闭池子,默认参数为True,表示在所有异步任务完成后关闭池子,否则立即关闭。

示例说明

使用ThreadPoolExecutor处理并发问题

通过以下示例,演示如何使用ThreadPoolExecutor类处理并发问题。在示例中,我们需要从几个网站上下载图片并保存到本地文件中。本例使用threading模块进行下载。

import urllib.request
import threading
import os
from concurrent.futures import ThreadPoolExecutor

def download(url, filename):
    urllib.request.urlretrieve(url, filename)

def main():
    urls = [
        'https://www.example.com/image1.jpg',
        'https://www.example.com/image2.jpg',
        'https://www.example.com/image3.jpg'
    ]
    with ThreadPoolExecutor() as executor:
        for url in urls:
            # 将下载任务提交到线程池中
            executor.submit(download, url, os.path.basename(url))

if __name__ == '__main__':
    main()

在示例中,我们首先定义了一个download()函数,用于从指定的URL下载图片并保存到本地文件中。接下来,我们使用ThreadPoolExecutor类创建了一个线程池,并将下载任务提交到线程池中。

使用ProcessPoolExecutor处理并发问题

通过以下示例,演示如何使用ProcessPoolExecutor类处理并发问题。在示例中,我们需要对一些URL进行Ping测试,并输出Ping的结果。本例使用multiprocessing模块进行Ping测试。

import subprocess
from concurrent.futures import ProcessPoolExecutor

def ping(url):
    # 注意:Windows下的ping参数与*nix不同
    cmd = ['-n', '3', '-w', '1000', url] if os.name == 'nt' else ['ping', '-c', '3', '-W', '1', url]
    result = subprocess.run(cmd, stderr=subprocess.PIPE)
    if result.returncode == 0:
        print(f'{url}: Ping Ok')
    else:
        print(f'{url}: Ping Failed')

def main():
    urls = [
        'www.baidu.com',
        'www.google.com',
        'www.example.com'
    ]
    with ProcessPoolExecutor() as executor:
        for url in urls:
            # 将Ping任务提交到进程池中
            executor.submit(ping, url)

if __name__ == '__main__':
    main()

在示例中,我们首先定义了一个ping()函数,用于对指定的URL进行Ping测试。接下来,我们使用ProcessPoolExecutor类创建了一个进程池,并将Ping任务提交到进程池中。