首页 > 解决方案 > 如何使用 Python 同时发送 10,000 个 HTTP 请求

问题描述

我需要从前 100 万个域中获取 HTTP GET 响应,并且我想打开尽可能多的并发线程,以便更快地完成它。我发现的唯一相关帖子是用 Python 发送 100,000 个 HTTP 请求的最快方法是什么? 并且该解决方案使用 concurrent.futures 按预期工作。

但是,问题是当我将工人数量设置得更高时,性能增益似乎停滞不前,也就是说,如果我将工人数量设置为 1000 或 10,000,我感觉不到任何差异。我在付费 EC2 实例上运行它,我可以看到我只使用了可用 CPU 和内存的一小部分。不知道发生了什么,我可以创建多少个并发线程有限制吗?我可以超越限制吗?

标签: pythonhttpconcurrency

解决方案


我发现 urllib3 和请求之间没有太大区别(请求可能更快)。我会使用异步库,因为这是一个主要用例。

from gevent import monkey, spawn, joinall
monkey.patch_all()
import urllib3, certifi
from time import time

threads = []
url = 'https://www.google.com'
upool = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where(), num_pools=20,  block=False)

t0 = time()
for i in xrange(10000):
    threads.append(spawn(upool.request,'GET',url))

x = joinall(threads)

print len(x)
print time() - t0

true请注意,您可以通过添加来限制一次使用的连接数block

* 多处理更新 *

from gevent import monkey, spawn, joinall
monkey.patch_all()
import urllib3, certifi
from time import time
import gipc

worker = {}
num_threads = 1000

def fetch(num_threads, url, cpu):
    print('starting {}'.format(cpu))
    threads = []
    upool = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where(), num_pools=20, block=False)
    t0 = time()
    for i in xrange(num_threads):
        threads.append(spawn(upool.request, 'GET', url))
    x = joinall(threads)
    return x, time() - t0

def count_cpus():
    import multiprocessing
    cpus = multiprocessing.cpu_count()
    print(cpus)
    return cpus

def multicore(url):
    global worker
    with gipc.pipe() as (r,w):
        for cpu in range(count_cpus()):
            worker[str(cpu)] = gipc.start_process(target=fetch, args=(num_threads, url, cpu))
    for work in worker:
        worker[work].join()
    return worker

if __name__ == '__main__':
    multicore('https://www.google.com')

    for work in worker:
        print worker[work]

推荐阅读