【问题标题】:Best way to limit concurrent http requests in python (no threads)?限制python中并发http请求的最佳方法(无线程)?
【发布时间】:2021-07-06 12:30:50
【问题描述】:

我有兴趣为异步函数调用创建一个池(它们将是 HTTP 请求),但是我想在一个线程中完成所有事情。这样做的原因是产生多个线程会浪费资源(线程什么都不做,只是等待响应)。

import asyncio
import aiohttp

import some_library as pool

POOL_LIMIT = 3

urls = ["example.com/28409078",
"example.com/31145880",
"example.com/54622752",
"example.com/48008963",
"example.com/82016326",
"example.com/75587921",
"example.com/2988065",
"example.com/47574087",
"example.com/13478021",
"example.com/46041669"]

def get(url):
  # return some promise here

# now perform the async operations
pool(limit=POOL_LIMIT, urls, get)


是否有可以为我管理异步池的 python 库?在 Node.js 中,看起来有一个库可以做一些接近我想做的事情:https://github.com/rxaviers/async-pool

【问题讨论】:

  • 您能说说您使用的是哪个库吗?
  • 如果有帮助,我正在使用 asyncioaiohttp
  • asyncio 库在设计上是单线程的。如果你想限制并发使用semaphore。另请注意,默认情况下,aiohttp 的客户端会话允许 100 个并发连接。更多详情请见docs.aiohttp.org/en/stable/…

标签: python asynchronous web-scraping


【解决方案1】:

在这里,我使用基本的asyncio 函数实现了一个池。

工作:

  • 池以 maxsize 个任务开始
  • 当第一个任务完成时,它将下一个任务添加到队列中并打印其结果
  • 类似地,对于每个单独的任务完成,它会添加另一个任务,直到达到最大尺寸

代码:

import asyncio

async def pool(tasks, maxsize=3):
    pending = [tasks.pop(0) for _ in range(maxsize) if tasks]
    while pending:
        (done, pending) = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
        while True:
             if (not tasks) or (len(pending) >= maxsize):
                  break
             pending.add(tasks.pop(0))
        for task in done:
             print(task.result())
    print("POOL COMPLETED")

例如,您可以像这里一样创建任务和池:

async def work(index, sleep_time):
    await asyncio.sleep(sleep_time)
    return f"task {index} done"

tasks = [work(i, 1) for i in range(10)]

现在运行任务调用 asyncio.run

asyncio.run(pool(tasks, 3))

这只会并行运行 3 个任务

【讨论】:

    【解决方案2】:

    我不知道是否有一个流行的图书馆。这是一个简单的方法:

    async def get(url):
      # return some promise here
    
    async def processQueue():
      while len(urls):
        url = urls.pop()
        await get(url)
    
    async def main():
      await asyncio.gather(
        processQueue(),
        processQueue(),
        processQueue()
      )
    
    asyncio.run(main())
    

    你可能在 pop() 之前需要一个锁,我不确定。

    【讨论】:

      猜你喜欢
      • 2019-02-05
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 2013-03-20
      • 2013-12-05
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多