python并发执行request请求

简介: 选择哪种并发方式取决于我们的具体需求。对于I/O密集型任务,多线程或异步I/O通常是更好的选择;对于CPU密集型任务,多进程可能是更好的选择。此外,异步I/O通常比多线程具有更好的性能,特别是在高并发的网络应用中。

在Python中,我们可以使用requests库来发送HTTP请求,并使用threadingmultiprocessingasyncio(配合aiohttp)或concurrent.futures等库来并发执行这些请求。这里,我将为我们展示使用concurrent.futures.ThreadPoolExecutorrequests库并发执行HTTP请求的示例。

1.使用concurrent.futures.ThreadPoolExecutor并发发送请求示例

首先,我们需要安装requests库(如果还没有安装的话):

pip install requests

然后,我们可以使用以下代码来并发地发送HTTP GET请求:

import concurrent.futures  
import requests  
# 假设我们有一个URL列表  
urls = [  
    'http://example.com/api/data1',  
    'http://example.com/api/data2',  
    'http://example.com/api/data3',  
    # ... 添加更多URL  
]  
# 定义一个函数,该函数接收一个URL,发送GET请求,并打印响应内容  
def fetch_data(url):  
    try:  
        response = requests.get(url)  
        response.raise_for_status()  # 如果请求失败(例如,4xx、5xx),则抛出HTTPError异常  
        print(f"URL: {url}, Status Code: {response.status_code}, Content: {response.text[:100]}...")  
    except requests.RequestException as e:  
        print(f"Error fetching {url}: {e}")  
# 使用ThreadPoolExecutor并发地执行fetch_data函数  
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:  # 你可以根据需要调整max_workers的值  
    future_to_url = {executor.submit(fetch_data, url): url for url in urls}  
    for future in concurrent.futures.as_completed(future_to_url):  
        url = future_to_url[future]  
        try:  
            # 通过调用future.result()来获取函数的返回值,这会阻塞,直到结果可用  
            # 但是请注意,这里我们只是打印结果,没有返回值,所以调用future.result()只是为了等待函数完成  
            future.result()  
        except Exception as exc:  
            print(f'Generated an exception for {url}: {exc}')

在这里简单解释一下这个代码示例:

  1. 我们首先定义了一个URL列表,这些是我们想要并发访问的URL。
  2. 然后,我们定义了一个函数fetch_data,它接收一个URL作为参数,发送GET请求,并打印响应的状态码和内容(只打印前100个字符以节省空间)。如果发生任何请求异常(例如,网络错误、无效的URL、服务器错误等),它会捕获这些异常并打印错误消息。
  3. 使用concurrent.futures.ThreadPoolExecutor,我们可以轻松地并发执行fetch_data函数。我们创建了一个ThreadPoolExecutor实例,并指定了最大工作线程数(在这个例子中是5,但我们可以根据需要调整这个值)。然后,我们使用列表推导式将每个URL与一个Future对象关联起来,该对象表示异步执行的函数。
  4. 最后,我们使用as_completed函数迭代所有完成的Future对象。对于每个完成的Future对象,我们调用result方法来获取函数的返回值(尽管在这个例子中我们没有使用返回值)。如果函数执行期间发生任何异常,result方法会重新引发该异常,我们可以捕获并处理它。


这个示例展示了如何使用Python的concurrent.futures模块来并发地发送HTTP请求。这种方法在IO密集型任务(如网络请求)上特别有效,因为它允许在等待IO操作完成时释放CPU资源供其他线程使用。

2.requests库并发发送HTTP GET请求的完整Python代码示例

以下是一个使用concurrent.futures.ThreadPoolExecutorrequests库并发发送HTTP GET请求的完整Python代码示例:

import concurrent.futures  
import requests  
# 假设我们有一个URL列表  
urls = [  
    'https://www.example.com',  
    'https://httpbin.org/get',  
    'https://api.example.com/some/endpoint',  
    # ... 添加更多URL  
]  
# 定义一个函数来发送GET请求并处理响应  
def fetch_url(url):  
    try:  
        response = requests.get(url, timeout=5)  # 设置超时为5秒  
        response.raise_for_status()  # 如果请求失败,抛出HTTPError异常  
        return response.text  # 返回响应内容,这里只是作为示例,实际使用中可能不需要返回  
    except requests.RequestException as e:  
        print(f"Error fetching {url}: {e}")  
        return None
# 使用ThreadPoolExecutor并发地发送请求  
def fetch_all_urls(urls):  
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:  
        # 使用executor.map来自动处理迭代和Future的获取  
        results = executor.map(fetch_url, urls)  
    # 处理结果(这里只是简单地打印出来)  
    for result in results:  
        if result is not None:  
            print(f"Fetched content from a URL (truncated): {result[:100]}...")  
# 调用函数  
fetch_all_urls(urls)

在这个示例中,我们定义了一个fetch_url函数,它接收一个URL,发送GET请求,并返回响应内容(或在出错时返回None)。然后,我们定义了一个fetch_all_urls函数,它使用ThreadPoolExecutor并发地调用fetch_url函数,并将结果收集在一个迭代器中。最后,我们遍历这个迭代器,并打印出每个成功获取到的响应内容(这里只打印了前100个字符作为示例)。


请注意,我们在requests.get中设置了一个超时参数(timeout=5),这是为了防止某个请求因为网络问题或其他原因而无限期地等待。在实际应用中,根据我们的需求调整这个值是很重要的。


此外,我们还使用了executor.map来自动处理迭代和Future的获取。executor.map函数会返回一个迭代器,它会产生fetch_url函数的返回值,这些值在函数完成后会自动从相应的Future对象中提取出来。这使得代码更加简洁,并且减少了显式处理Future对象的需要。

3.如何在Python中实现并发编程

在Python中实现并发编程,主要有以下几种方式:

(1)使用threading模块threading模块提供了多线程编程的API。Python的线程是全局解释器锁(GIL)下的线程,这意味着在任意时刻只有一个线程能够执行Python字节码。然而,对于I/O密集型任务(如网络请求),多线程仍然可以通过并发地等待I/O操作来提高性能。


示例:

import threading  
import requests  
def fetch_url(url):  
    try:  
        response = requests.get(url)  
        response.raise_for_status()  
        print(f"URL: {url}, Status Code: {response.status_code}")  
    except requests.RequestException as e:  
        print(f"Error fetching {url}: {e}")  
threads = []  
for url in urls:  
    t = threading.Thread(target=fetch_url, args=(url,))  
    threads.append(t)  
    t.start()  
# 等待所有线程完成  
for t in threads:  
    t.join()

(2)使用multiprocessing模块multiprocessing模块提供了跨多个Python解释器的进程间并行处理。这对于CPU密集型任务特别有用,因为每个进程都有自己的Python解释器和GIL,可以充分利用多核CPU的并行处理能力。


示例:

from multiprocessing import Pool  
import requests  
def fetch_url(url):  
    try:  
        response = requests.get(url)  
        response.raise_for_status()  
        return f"URL: {url}, Status Code: {response.status_code}"
    except requests.RequestException as e:  
        return f"Error fetching {url}: {e}"
with Pool(processes=4) as pool:  # 设定进程池的大小  
    results = pool.map(fetch_url, urls)  
for result in results:  
    print(result)

(3)使用asyncio模块(针对异步I/O)asyncio是Python 3.4+中引入的用于编写单线程并发代码的库,特别适合编写网络客户端和服务器。它使用协程(coroutine)和事件循环(event loop)来管理并发。


示例(使用aiohttp库进行异步HTTP请求):

import asyncio  
import aiohttp  
async def fetch_url(url, session):  
    async with session.get(url) as response:  
        return await response.text()  
async def main():  
    async with aiohttp.ClientSession() as session:  
        tasks = []  
        for url in urls:  
            task = asyncio.create_task(fetch_url(url, session))  
            tasks.append(task)  
        results = await asyncio.gather(*tasks)  
        for result, url in zip(results, urls):  
            print(f"URL: {url}, Content: {result[:100]}...")  
# Python 3.7+ 可以使用下面的方式运行主协程  
asyncio.run(main())

注意:asyncio.run()是在Python 3.7中引入的,用于运行顶层入口点函数。在Python 3.6及以下版本中,我们需要自己设置和运行事件循环。


(4)使用concurrent.futures模块concurrent.futures模块提供了高层次的接口,可以轻松地编写并发代码。它提供了ThreadPoolExecutor(用于线程池)和ProcessPoolExecutor(用于进程池)。


前面已经给出了ThreadPoolExecutor的示例,这里不再重复。ProcessPoolExecutor的用法与ThreadPoolExecutor类似,只是它是基于进程的。


选择哪种并发方式取决于我们的具体需求。对于I/O密集型任务,多线程或异步I/O通常是更好的选择;对于CPU密集型任务,多进程可能是更好的选择。此外,异步I/O通常比多线程具有更好的性能,特别是在高并发的网络应用中。

相关文章
|
2月前
|
JSON API 开发者
Python网络编程新纪元:urllib与requests库,让你的HTTP请求无所不能
【7月更文挑战第31天】互联网的发展使网络编程成为软件开发的关键部分. Python以简洁、功能强大著称, 在此领域尤显突出. `urllib`作为标准库, 自Python初期便支持URL处理, 如读取URL (`urllib.request`) 和解析 (`urllib.parse`). 尽管API底层, 但奠定了网络编程基础.
38 4
|
22天前
|
JSON API 数据格式
Python网络编程:HTTP请求(requests模块)
在现代编程中,HTTP请求几乎无处不在。无论是数据抓取、API调用还是与远程服务器进行交互,HTTP请求都是不可或缺的一部分。在Python中,requests模块被广泛认为是发送HTTP请求的最简便和强大的工具之一。本文将详细介绍requests模块的功能,并通过一个综合示例展示其应用。
|
2月前
|
并行计算 Python
python 并发与并行
【7月更文挑战第21天】
32 5
python 并发与并行
|
26天前
|
开发者 Python
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
100 1
|
30天前
|
JSON API 开发者
Python学习Get方式通过商品 ID请求 获取拼多多商品详情数据接口
拼多多商品详情数据接口服务使开发者或商家能编程获取平台商品详情,涵盖标题、价格、销量等关键信息,助力市场分析与决策。使用前需注册开发者账号并获取API密钥;构造含商品ID等参数的请求URL后发送至API服务器;接口以JSON格式返回数据。应用场景包括商品销售分析、选品、品牌口碑挖掘及竞品分析,为商家提供强大数据支持。
|
2月前
|
存储 运维 Java
函数计算产品使用问题之如何使用Python的requests库向HTTP服务器发送GET请求
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
2月前
|
并行计算 监控 数据处理
构建高效Python应用:并发与异步编程的实战秘籍,IO与CPU密集型任务一网打尽!
【7月更文挑战第16天】Python并发异步提升性能:使用`asyncio`处理IO密集型任务,如网络请求,借助事件循环实现非阻塞;`multiprocessing`模块用于CPU密集型任务,绕过GIL进行并行计算。通过任务类型识别、任务分割、避免共享状态、利用现代库和性能调优,实现高效编程。示例代码展示异步HTTP请求和多进程数据处理。
43 8
|
2月前
|
算法 Java 程序员
解锁Python高效之道:并发与异步在IO与CPU密集型任务中的精准打击策略!
【7月更文挑战第17天】在数据驱动时代,Python凭借其优雅语法和强大库支持成为并发处理大规模数据的首选。并发与异步编程是关键,包括多线程、多进程和异步IO。对于IO密集型任务,如网络请求,可使用`concurrent.futures`和`asyncio`;CPU密集型任务则推荐多进程,如`multiprocessing`;`asyncio`适用于混合任务,实现等待IO时执行CPU任务。通过这些工具,开发者能有效优化资源,提升系统性能。
67 4
|
2月前
|
分布式计算 并行计算 Java
Python并发风暴来袭!IO密集型与CPU密集型任务并发策略大比拼,你站哪队?
【7月更文挑战第17天】Python并发处理IO密集型(如网络请求)与CPU密集型(如数学计算)任务。IO密集型适合多线程和异步IO,如`ThreadPoolExecutor`进行网页下载;CPU密集型推荐多进程,如`multiprocessing`模块进行并行计算。选择取决于任务类型,理解任务特性是关键,以实现最佳效率。
39 4
|
2月前
|
开发框架 并行计算 .NET
脑洞大开!Python并发与异步编程的哲学思考:IO密集型与CPU密集型任务的智慧选择!
【7月更文挑战第18天】在Python中,异步编程(如`asyncio`)适合处理IO密集型任务,通过非阻塞操作提高响应性,例如使用`aiohttp`进行异步HTTP请求。而对于CPU密集型任务,由于GIL的存在,多进程(`multiprocessing`)能实现并行计算,如使用进程池进行大量计算。明智选择并发模型是性能优化的关键,体现了对任务特性和编程哲学的深刻理解。
28 2
下一篇
DDNS