Является ли мультиинтерфейс в curl быстрее или эффективнее, чем использование нескольких простых интерфейсов?

Я делаю что-то, что включает в себя pycurl, так как pycurl зависит от libcurl, я читал его документацию и наткнулся на этот мульти-интерфейс, где вы можете выполнять несколько передач, используя один мульти-объект. Мне было интересно, будет ли это быстрее/эффективнее использовать память, чем иметь несколько простых интерфейсов? Мне было интересно, в чем преимущество этого подхода, поскольку на сайте почти не говорится:

«Включите несколько одновременных передач в одном потоке, не усложняя приложение».


person Aditya    schedule 10.08.2014    source источник
comment
Из любопытства, есть ли причина, по которой вы используете pycurl вместо stdlib, requests или чего-то еще более Pythonic? Иногда для этого есть веские причины, но чаще всего я уже знаю, как это хорошо сделать в libcurl, и я ожидаю, что это переведется в pycurl, что здесь, похоже, не так.   -  person abarnert    schedule 10.08.2014
comment
@abarnert Я ищу наиболее эффективное решение (время выполнения или память). Я знаю только команды Curl и Wget из unix. Поэтому я начал искать способы использования Curl в Python и наткнулся на PyCurl. Поскольку я потратил на PyCurl только последний час и еще не написал никакого кода, я готов перейти на что-то другое. Поскольку PyCurl использует Libcurl, написанную на C, я предположил, что это будет очень эффективно. Я знаю, что это может быть неправдой. То, что я создаю, — это слово, означающее утилиту поиска. Который гуглит значения около 200 или около того слов.   -  person Aditya    schedule 10.08.2014
comment
Почему вы ищете наиболее эффективное решение? Ограничивающим фактором по времени будет ваша сеть или удаленный сервер; любое время, потраченное впустую на вашем сервере, не имеет значения. Ограничивающим фактором по объему будет 200 полных страниц; любая потерянная дюжина байтов здесь или там не имеет значения. Это преждевременная оптимизация в худшем случае.   -  person abarnert    schedule 10.08.2014


Ответы (2)


Вы пытаетесь оптимизировать то, что вообще не имеет значения.

Если вы хотите загрузить 200 URL-адресов как можно быстрее, вы потратите 99,99% своего времени на ожидание этих 200 запросов, что ограничено вашей сетью и/или сервером(-ами), с которого вы загружаете. Ключом к оптимизации является правильное количество одновременных запросов. Все, что вы можете сделать, чтобы сократить последние 0,01%, не окажет видимого влияния на вашу программу. (См. Закон Амдала.)

Разные источники дают разные рекомендации, но обычно это где-то между 6-12 запросами, не более 2-4 на один и тот же сервер. Поскольку вы извлекаете их все из Google, я бы предложил начать с 4 одновременных запросов, а затем, если это недостаточно быстро, настроить это число, пока не получите наилучшие результаты.

Что касается места, стоимость хранения 200 страниц будет намного превышать стоимость нескольких десятков байтов здесь и там для накладных расходов. Опять же, вы хотите оптимизировать эти 200 страниц — сохраняя их на диск, а не в память, анализируя их по мере поступления, вместо того, чтобы загружать все, а затем анализировать все и т. д.

В любом случае, вместо того, чтобы смотреть, какие инструменты командной строки у вас есть, и пытаться найти библиотеку, похожую на них, ищите библиотеки напрямую. pycurl может быть полезен в некоторых случаях, например, когда вы пытаетесь сделать что-то сложное и уже знаете, как это сделать с помощью libcurl, но в целом будет намного проще использовать либо модули stdlib, такие как urllib, либо третьи Модули для вечеринок разработаны максимально простыми, например, requests.

основной пример для ThreadPoolExecutor в документации показывает, как делать именно то, что вы хотите сделать. (Если вы используете Python 2.x, вам потребуется pip install futures, чтобы получить резервную копию для ThreadPoolExecutor, и использовать urllib2 вместо urllib.request, но в остальном код будет идентичным.)

person abarnert    schedule 10.08.2014
comment
Очень хорошо сказано, сэр. Чтение вашего ответа заставило меня задуматься обо всем этом, и я хотел узнать больше о том, как было установлено ограничение на 2-4 запроса к одному и тому же серверу. - person Aditya; 10.08.2014
comment
Это не всегда так. Все зависит от задачи. Необходимость парсить 1000 страниц одновременно с гигабитным (или 10-гигабитным) соединением — типичный сценарий для современных парсеров. Но вы не можете позволить себе параллельно запускать 1000 воркеров. Curl multi делает это с легкостью в один поток! - person Corneliu Maftuleac; 07.02.2018

Наличие нескольких простых интерфейсов, работающих одновременно в одном потоке, означает создание собственного реактора и управление curl на более низком уровне. Это болезненно в C и столь же болезненно в Python, поэтому libcurl предлагает и рекомендует multi.

Но здесь ключевое значение имеет «в том же потоке». Вы также можете создать пул потоков и добавить в него простые экземпляры. В C это все еще может быть болезненно; в Python это очень просто. На самом деле, первый пример в документации по использованию concurrent.futures.ThreadPoolExecutor делает что-то похожее, но на самом деле более сложное, чем вам нужно здесь, и это всего лишь несколько строк кода.

Если вы сравниваете мульти и простой с ручным реактором, простота является основным преимуществом. В C вы могли бы легко реализовать более эффективный реактор, чем тот, который использует libcurl; в Python это может быть правдой, а может и не быть. Но в любом языке затраты производительности на переключение между несколькими сетевыми запросами будут настолько малы по сравнению со всеми остальными вашими действиями, особенно ожиданием этих сетевых запросов, что вряд ли когда-либо будут иметь значение.

Если вы сравниваете многопоточность и простоту с пулом потоков, то реактор определенно может превзойти потоки (за исключением платформ, где вы можете связать пул потоков с проактором, как с портами завершения ввода-вывода Windows), особенно для огромных чисел. одновременных подключений. Кроме того, каждому потоку нужен собственный стек, что обычно означает выделение около 1 МБ страниц памяти (хотя не все они используются), что может стать серьезной проблемой в 32-разрядной среде для огромного количества подключений. Вот почему очень немногие серьезные серверы используют потоки для соединений. Но для клиента, который устанавливает несколько подключений, все это не имеет значения; опять же, затраты, связанные с потерей 8 потоков по сравнению с использованием реактора, будут настолько малы по сравнению с реальными затратами на вашу программу, что они не будут иметь значения.

person abarnert    schedule 10.08.2014