Python asyncio / aiohttp:ValueError:Windows上select()中的文件描述符太多

时间:2017-12-06 13:23:13

标签: python python-3.x async-await python-asyncio aiohttp

大家好, 我在尝试理解asyncio和aiohttp并使两者正常工作时遇到了麻烦。不仅我不能正确理解我在做什么,此时我遇到了一个我不知道如何解决的问题。

我使用Windows 10 64位,最新更新。

以下代码使用asyncio返回标题中Content-Type中不包含html的页面列表。

import asyncio
import aiohttp

MAXitems = 30

async def getHeaders(url, session, sema):
    async with session:
        async with sema:
            try:
                async with session.head(url) as response:
                    try:
                        if "html" in response.headers["Content-Type"]:
                            return url, True
                        else:
                            return url, False
                    except:
                        return url, False
            except:
                return url, False


def checkUrlsWithoutHtml(listOfUrls):
    headersWithoutHtml = set()
    while(len(listOfUrls) != 0):
        blockurls = []
        print(len(listOfUrls))
        items = 0
        for num in range(0, len(listOfUrls)):
            if num < MAXitems:
                blockurls.append(listOfUrls[num - items])
                listOfUrls.remove(listOfUrls[num - items])
                items +=1
        loop = asyncio.get_event_loop()
        semaphoreHeaders = asyncio.Semaphore(50)
        session = aiohttp.ClientSession()
        data = loop.run_until_complete(asyncio.gather(*(getHeaders(url, session, semaphoreHeaders) for url in blockurls)))
        for header in data:
            if False == header[1]:
                headersWithoutHtml.add(header)
    return headersWithoutHtml


listOfUrls = ['http://www.google.com', 'http://www.reddit.com']
headersWithoutHtml=  checkUrlsWithoutHtml(listOfUrls)

for header in headersWithoutHtml:
    print(header[0])

当我运行它时,让我们说,2000 url(有时)它返回类似于:

data = loop.run_until_complete(asyncio.gather(*(getHeaders(url, session, semaphoreHeaders) for url in blockurls)))
  File "USER\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 454, in run_until_complete
    self.run_forever()
  File "USER\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 421, in run_forever
    self._run_once()
  File "USER\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 1390, in _run_once
    event_list = self._selector.select(timeout)
  File "USER\AppData\Local\Programs\Python\Python36-32\lib\selectors.py", line 323, in select
    r, w, _ = self._select(self._readers, self._writers, [], timeout)
  File "USER\AppData\Local\Programs\Python\Python36-32\lib\selectors.py", line 314, in _select
    r, w, x = select.select(r, w, w, timeout)
ValueError: too many file descriptors in select()

注1 :我在用户中使用USER编辑了我的名字。

Note2 :无论出于何种原因reddit.com返回,因为它不包含HTML,这是一个完全独立的问题,我将尝试解决,但是如果你注意到其他一些不一致的问题我的代码可以修复它,请指出它。

Note3 :我的代码构造糟糕,因为我试图改变很多东西来尝试调试这个问题,但我没有运气。

我已经听说过这是Windows的一个限制,没有办法绕过它,问题是:

a)我直接不明白select()&#34;中有多少文件描述符?装置

b)我无法解决Windows无法解决的问题?我已经看到人们用asyncio和aiohttp推送了成千上万的请求,但即使我的chuncking,我也不能在没有得到值错误的情况下推动30-50?

编辑:结果是MAXitems = 10它还没有让我崩溃,但是由于我无法遵循这种模式,我不知道为什么或如何告诉我任何事情

Edit2 :没关系,它需要更多的时间来崩溃,但最终甚至用MAXitems = 10

3 个答案:

答案 0 :(得分:4)

默认情况下,Windows在asyncio循环中只能使用64个套接字。这是基础select() API调用的限制。

要提高限额,请使用ProactorEventLoop。安装说明为here

答案 1 :(得分:1)

我遇到了同样的问题。不是100%确定这可以保证有效,但请尝试替换它:

session = aiohttp.ClientSession()

用这个:

connector = aiohttp.TCPConnector(limit=60)
session = aiohttp.ClientSession(connector=connector)

默认情况下,limit设置为100(docs),这意味着客户端一次可以打开100个并发连接。正如安德鲁所说,Windows一次只能打开64个套接字,所以我们提供的数字低于64个。

答案 2 :(得分:0)

#Add to call area
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)