【问题标题】:How to send 10,000 HTTP requests concurrently using Python如何使用 Python 同时发送 10,000 个 HTTP 请求
【发布时间】:2019-07-18 16:19:44
【问题描述】:

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

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

【问题讨论】:

    标签: python http concurrency


    【解决方案1】:

    我发现 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]
    

    【讨论】:

    • 10000 个连接在 128.472000122 秒内完成。
    • 我正在看这个博客:pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/… 它似乎比 urllib 快得多,但理解起来不太直观。开10000个线程,每个人发一个请求,然后10000个请求瞬间完成?
    • 而且,我在具有 8 个 vCPU 和 32G 内存的 EC2 t3.2xlarge 上运行您的确切代码,它会抛出“设备或资源忙”错误,我只能执行 5000 次并且可以在大约 50 秒内完成它.你用什么怪物机一次跑10000?
    • 请记住,这仍然是单线程的。您可以在此基础上利用多进程来利用更多 CPU。
    • 你能给我一个提示吗?我不是多线程或进程程序员方面的专家,但只想完成工作。我知道笨拙的方法是在 Linux 中手动键入并运行命令两次,然后它的运行速度确实快了 2 倍。但是有没有一种直观且简单的方法可以用 Python 来完成呢?
    猜你喜欢
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    相关资源
    最近更新 更多