python3.6 使用 aiohttp 和 asyncio 启动 100 万个请求
python3.6 start 1 million requests with aiohttp and asyncio
我正在尝试连续 10 次使用 aiohttp 和 asyncio 发出 100 万个请求,每次 10k。当我打印每个请求的开始时间时,我发现这 100 万个请求不是在非常封闭的时间开始的,而是在 serval 分钟内开始的。在我的理解中,100 万个请求将在没有任何等待的情况下发送(或者只是说以微秒为单位?)希望有人可以帮助我提出如何更改代码的建议,我的代码如下。提前致谢!
import asyncio
import requests
import json
import pymysql
from aiohttp import ClientSession
from datetime import datetime
import uvloop
# login config
URL_LOGIN = "https://test.com/user/login"
APP_ID = "sample_app_id"
APP_SECRET = "sample_secret"
async def login_user(phone, password, session, i):
start_time = datetime.now()
h = {
"Content-Type": "application/json"
}
data = {
"phone": phone,
"password": password,
"appid": APP_ID,
"appsecret": APP_SECRET
}
try:
async with session.post(url=URL_LOGIN, data=json.dumps(data), headers=h) as response:
r = await response.read()
end_time = datetime.now()
cost = (end_time-start_time).seconds
msg = "number %d request,start_time:%s, cost_time: %d, response: %s\n" % (i, start_time, cost, r.decode())
print("running %d" % i, datetime.now())
except Exception as e:
print("running %d" % i)
msg = "number %d request raise error" % i+str(e)+"\n"
with open("log", "a+") as f:
f.write(msg)
async def bound_login(sem, phone, password, session, i):
async with sem:
await login_user(phone, password, session, i)
async def run_login(num):
tasks = []
sem = asyncio.Semaphore(10000)
async with ClientSession() as session:
for i in range(num):
task = asyncio.ensure_future(bound_login(sem, str(18300000000+i), "123456", session, i))
tasks.append(task)
responses = asyncio.gather(*tasks)
await responses
start = datetime.now()
number = 100000
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
future = asyncio.ensure_future(run_login(number))
When I print the start time of each request, I found that the 1 million requests are NOT start at a very closed time but in serval minutes.
您的代码确实发出了总共 100 万个请求,但限制条件是在任何给定时间并行运行的请求不超过 1 万个。这就像有 10k 个请求槽供您使用 - 前 10,000 个请求将立即开始,但第 10,001 个请求必须等待上一个请求完成才能获得空闲槽。
这就是为什么 100 万个请求无法立即或接近即时启动的原因,其中大部分必须等待某些下载完成,这需要时间。
In my understanding, the 1 million requests will be sent without any wait
当前代码明确让请求等待,以防止超过 10k 个请求并行 运行。如果您真的想(尝试)发出一百万个并行请求,请删除信号量并使用 connector 创建 ClientSession
并将 limit
设置为 None
.
但是请注意,由于操作系统和硬件的限制,维持一百万个打开的连接可能无法正常工作。 (您应该仍然能够近乎即时地启动 连接,但我希望它们中的大多数会在不久之后异常退出。)
我正在尝试连续 10 次使用 aiohttp 和 asyncio 发出 100 万个请求,每次 10k。当我打印每个请求的开始时间时,我发现这 100 万个请求不是在非常封闭的时间开始的,而是在 serval 分钟内开始的。在我的理解中,100 万个请求将在没有任何等待的情况下发送(或者只是说以微秒为单位?)希望有人可以帮助我提出如何更改代码的建议,我的代码如下。提前致谢!
import asyncio
import requests
import json
import pymysql
from aiohttp import ClientSession
from datetime import datetime
import uvloop
# login config
URL_LOGIN = "https://test.com/user/login"
APP_ID = "sample_app_id"
APP_SECRET = "sample_secret"
async def login_user(phone, password, session, i):
start_time = datetime.now()
h = {
"Content-Type": "application/json"
}
data = {
"phone": phone,
"password": password,
"appid": APP_ID,
"appsecret": APP_SECRET
}
try:
async with session.post(url=URL_LOGIN, data=json.dumps(data), headers=h) as response:
r = await response.read()
end_time = datetime.now()
cost = (end_time-start_time).seconds
msg = "number %d request,start_time:%s, cost_time: %d, response: %s\n" % (i, start_time, cost, r.decode())
print("running %d" % i, datetime.now())
except Exception as e:
print("running %d" % i)
msg = "number %d request raise error" % i+str(e)+"\n"
with open("log", "a+") as f:
f.write(msg)
async def bound_login(sem, phone, password, session, i):
async with sem:
await login_user(phone, password, session, i)
async def run_login(num):
tasks = []
sem = asyncio.Semaphore(10000)
async with ClientSession() as session:
for i in range(num):
task = asyncio.ensure_future(bound_login(sem, str(18300000000+i), "123456", session, i))
tasks.append(task)
responses = asyncio.gather(*tasks)
await responses
start = datetime.now()
number = 100000
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
future = asyncio.ensure_future(run_login(number))
When I print the start time of each request, I found that the 1 million requests are NOT start at a very closed time but in serval minutes.
您的代码确实发出了总共 100 万个请求,但限制条件是在任何给定时间并行运行的请求不超过 1 万个。这就像有 10k 个请求槽供您使用 - 前 10,000 个请求将立即开始,但第 10,001 个请求必须等待上一个请求完成才能获得空闲槽。
这就是为什么 100 万个请求无法立即或接近即时启动的原因,其中大部分必须等待某些下载完成,这需要时间。
In my understanding, the 1 million requests will be sent without any wait
当前代码明确让请求等待,以防止超过 10k 个请求并行 运行。如果您真的想(尝试)发出一百万个并行请求,请删除信号量并使用 connector 创建 ClientSession
并将 limit
设置为 None
.
但是请注意,由于操作系统和硬件的限制,维持一百万个打开的连接可能无法正常工作。 (您应该仍然能够近乎即时地启动 连接,但我希望它们中的大多数会在不久之后异常退出。)