迭代数据框的更快方法?
Faster way to iterate over dataframe?
我有一个数据框,其中每一行都是一条记录,我需要在 post 请求的正文中发送每条记录。现在我正在遍历数据框来完成这个。我受到每个记录必须单独 post 的事实的限制。有没有更快的方法来完成这个?
迭代数据框不是这里的问题。问题是您必须等待服务器响应您的每个请求。与 CPU 遍历数据帧所需的时间相比,网络请求需要花费大量时间。换句话说,您的程序是 I/O 绑定的,而不是 CPU 绑定的。
一种加快速度的方法是使用协程。假设您必须发出 1000 个请求。不是触发一个请求,而是等待响应,然后触发下一个请求,依此类推,您一次触发 1000 个请求并告诉 Python 等到您收到所有 1000 个响应。
由于您没有提供任何代码,这里有一个小程序来说明这一点:
import aiohttp
import asyncio
import numpy as np
import time
from typing import List
async def send_single_request(session: aiohttp.ClientSession, url: str):
async with session.get(url) as response:
return await response.json()
async def send_all_requests(urls: List[str]):
async with aiohttp.ClientSession() as session:
# Make 1 coroutine for each request
coroutines = [send_single_request(session, url) for url in urls]
# Wait until all coroutines have finished
return await asyncio.gather(*coroutines)
# We will make 10 requests to httpbin.org. Each request will take at least d
# seconds. If you were to fire them sequentially, they would have taken at least
# delays.sum() seconds to complete.
np.random.seed(42)
delays = np.random.randint(0, 5, 10)
urls = [f"https://httpbin.org/delay/{d}" for d in delays]
# Instead, we will fire all 10 requests at once, then wait until all 10 have
# finished.
t1 = time.time()
result = asyncio.run(send_all_requests(urls))
t2 = time.time()
print(f"Expected time: {delays.sum()} seconds")
print(f"Actual time: {t2 - t1:.2f} seconds")
输出:
Expected time: 28 seconds
Actual time: 4.57 seconds
您必须阅读一些关于协同程序及其工作原理的内容,但在大多数情况下,它们对于您的用例来说并不太复杂。这有几个警告:
- 您的所有请求必须相互独立。
- 服务器上的速率限制必须足以处理您的工作量。例如,如果它限制你每分钟 2 个请求,那么除了升级到不同的服务层之外别无他法。
我有一个数据框,其中每一行都是一条记录,我需要在 post 请求的正文中发送每条记录。现在我正在遍历数据框来完成这个。我受到每个记录必须单独 post 的事实的限制。有没有更快的方法来完成这个?
迭代数据框不是这里的问题。问题是您必须等待服务器响应您的每个请求。与 CPU 遍历数据帧所需的时间相比,网络请求需要花费大量时间。换句话说,您的程序是 I/O 绑定的,而不是 CPU 绑定的。
一种加快速度的方法是使用协程。假设您必须发出 1000 个请求。不是触发一个请求,而是等待响应,然后触发下一个请求,依此类推,您一次触发 1000 个请求并告诉 Python 等到您收到所有 1000 个响应。
由于您没有提供任何代码,这里有一个小程序来说明这一点:
import aiohttp
import asyncio
import numpy as np
import time
from typing import List
async def send_single_request(session: aiohttp.ClientSession, url: str):
async with session.get(url) as response:
return await response.json()
async def send_all_requests(urls: List[str]):
async with aiohttp.ClientSession() as session:
# Make 1 coroutine for each request
coroutines = [send_single_request(session, url) for url in urls]
# Wait until all coroutines have finished
return await asyncio.gather(*coroutines)
# We will make 10 requests to httpbin.org. Each request will take at least d
# seconds. If you were to fire them sequentially, they would have taken at least
# delays.sum() seconds to complete.
np.random.seed(42)
delays = np.random.randint(0, 5, 10)
urls = [f"https://httpbin.org/delay/{d}" for d in delays]
# Instead, we will fire all 10 requests at once, then wait until all 10 have
# finished.
t1 = time.time()
result = asyncio.run(send_all_requests(urls))
t2 = time.time()
print(f"Expected time: {delays.sum()} seconds")
print(f"Actual time: {t2 - t1:.2f} seconds")
输出:
Expected time: 28 seconds
Actual time: 4.57 seconds
您必须阅读一些关于协同程序及其工作原理的内容,但在大多数情况下,它们对于您的用例来说并不太复杂。这有几个警告:
- 您的所有请求必须相互独立。
- 服务器上的速率限制必须足以处理您的工作量。例如,如果它限制你每分钟 2 个请求,那么除了升级到不同的服务层之外别无他法。