最近在使用异步并发库写爬虫时,遇到了一个错误ValueError: too many file descriptors in select()
,这个错误大概是select使用了太多的文件描述符
。
查了查资料,发现asyncio中有用到select,而select是系统IO多路复用的一种方式,它会限制单个进程打开文件描述符的数量(linux是1024个,window是509个),如果超出这个值程序就会报错
下面是报错的代码(节选):
...
async def request():
url = 'http://127.0.0.1:5000'
print('Waiting for ', url)
result = await get(url)
print('Get response from ', url, 'Result: ', result)
def main():
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(request()) for _ in range(1000)]
loop.run_until_complete(asyncio.wait(tasks))
...
代码解析:
main函数中创建了1000个任务对象,然后将这些任务对象以awaitable
对象的形式注入到事件循环中,接下来事件循环会调用之前的协程对象。这些代码看似没有问题,但是创建任务对象时创建的太多了,远超出了系统的限制。
解决方案:
asyncio.Semaphore类是同步装置,用于限制并发请求
async with 则是异步上下文管理器
semaphore = asyncio.Semaphore(500)
async def request():
async with semaphore:
url = 'http://127.0.0.1:5000'
result = await get(url)
网友评论