), что означает, что клиент может иметь одновременно 100 открытых соединений. Как упоминал Эндрю, в Windows одновременно может быть открыто только 64 сокета, поэтому вместо них мы предоставляем число меньше 64.

т всем, у меня проблемы с попыткой понять asyncio и aiohttp и заставить их работать вместе должным образом. Мало того, что я не совсем правильно понимаю, что я делаю, на данный момент я столкнулся с проблемой, которую я понятия не имею, как решить.

Я использую Windows 10 64 бит, последнее обновление.

Следующий код возвращает мне список страниц, которые не содержат html в Content-Type в заголовке, используя asyncio.

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()

Note1: Я отредактировал свое имя с пользователем USER.

Заметка 2По какой-то причине возвращается reddit.com, поскольку он не содержит HTML, это совершенно отдельная проблема, которую я постараюсь решить, однако, если вы заметите в моем коде другое несоответствие, которое исправит это, укажите это.

Заметка 3Мой код плохо сконструирован, потому что я пытался изменить многие вещи, чтобы попытаться отладить эту проблему, но мне не повезло.

Я где-то слышал, что это ограничение Windows, и нет способа обойти его, проблема в том, что:

а) Я напрямую не понимаю, что означает «слишком много файловых дескрипторов в select ()».

б) Что я делаю неправильно, что Windows не может справиться? Я видел, как люди выдвигают тысячи запросов с помощью asyncio и aiohttp, но даже с помощью моего чанкинга я не могу нажать 30-50, не получив сообщение об ошибке значения?

редактировать: Оказывается, с MAXitems = 10 это еще не сломало меня, но, поскольку я не могу следовать шаблону, я понятия не имею, почему или как это мне что-то говорит.

Edit2: Несмотря ни на что, требовалось больше времени для сбоя, но в конечном итоге это произошло даже с MAXitems = 10

Ответы на вопрос(2)

что это сработает, но попробуйте заменить это:

session = aiohttp.ClientSession()

с этим:

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

По умолчаниюlimit установлено на 100 (документы), что означает, что клиент может иметь одновременно 100 открытых соединений. Как упоминал Эндрю, в Windows одновременно может быть открыто только 64 сокета, поэтому вместо них мы предоставляем число меньше 64.

Решение Вопроса

io. Это ограничение основныхВыбрать() Вызов API.

Для увеличения лимита, пожалуйста, используйтеProactorEventLoop, Инструкция по установке естьВот.

 Andrew Svetlov08 дек. 2017 г., 10:51
Вы написали, что обрабатываете около 2000 URL. HTTP-соединение возвращается во внутренний пул, но не освобождается немедленно. Вот как вы можете исчерпать лимит для открытых розеток.
 Josep07 дек. 2017 г., 22:59
а) Я не понимаю, как это на самом деле отвечает на мой вопрос. Я спросил, как можно насытить выборку, если я разбиваю данные на части, и это единственный скрипт, который я запускаю с aiohttp. Если только aiohttp не использует несколько соединений на одну ссылку. б) Ну, я собираюсь попробовать ваше решение позже, но _setmaxstdio имеет значение. Без этого он выдавал каждую тысячу ссылок "давай или бери", он сделал с ним более 5000+ без проблем, и единственная причина, по которой он остановился, заключается в том, что я прервал его. Редактировать: В любом случае, я дал вам разрешение на ответ на мой вопрос, спасибо.
 Andrew Svetlov07 дек. 2017 г., 19:39
а) да. aiohttp имеет ограничение 100 для числа одновременных соединений по умолчанию, оно больше 64. б) Я не использую Windows и не могу проверить_setmaxstdio но предел это макрос во время компиляции imho. Это не может быть изменено во время выполнения.
 Josep07 дек. 2017 г., 11:17
Спасибо! Несколько вопросов: а) Как это возможно, что я достигаю предела с порцией, которую я делаю? б) я пытался из win32file import _setmaxstdio _setmaxstdio (3072) с тех пор, как я опубликовал свой первоначальный вопрос, кажется, что он хорошо работает, работает ли он так же, как ProactorEventLoop?
 Josep09 дек. 2017 г., 21:49
Я изменил: loop = asyncio.get_event_loop () для: loop = asyncio.ProactorEventLoop () asyncio.set_event_loop (loop), и он вызывает: поднять NotImplementedError в файле "\ Python \ Python36-32 \ lib \ site-packages \ aiodns__в этом_.py ", строка 85, в _sock_state_cb self.loop.add_reader (fd, self._handle_event, fd, READ) Файл" \ Python \ Python36-32 \ lib \ asyncio \ events.py ", строка 453, в add_reader Редактировать: Я не знаю, как форматировать комментарии, извините

Ваш ответ на вопрос