Сравнение асинхронных http-клиентов

Insolita
3 min readMay 2, 2020

[English version here]

Вдохновившись занимательным интервью на канале Moreview c Сергеем Жуком, и циклом статей Fast Web Scraping With ReactPHP решила поэкспериментировать и выяснить, насколько всё-таки Fast, по сравнению с привычным Guzzle, который тоже умеет в асинхронные запросы через multicurl. А есть еще и amphp…

Задачу решила взять не слишком синтетическую — обойти список урлов, выдрать заголовки и записать в файлик. Неудачные адреса зафиксировать в другой файлик. Откуда взялся список история умалчивает, но их довольно много и однозначно есть как работающие, так и не работающие сайты. Ну и ддосить бенчмарками какой-то один конкретный сайт показалось менее этичным.

TLDR: Репо с тем что получилось и результаты — тут https://github.com/Insolita/php-async-benchmarks

Совсем идентичными клиенты не получились, у каждого свои нюансы. В асинхронных файлоклиентах не нашла возможности считывать файл построчно — только целиком или по размеру. С Amphp отдельная история, единственное решение в документации — https://amphp.org/http-client/concurrent просто отправлять запросы параллельно и потом постепенно обрабатывать ответы — более менее неплохо это срабатывает только на небольшом количестве запросов, на большом скорость обработки падает ниже плинтуса. Я, конечно, допускаю, что просто не умею его готовить — и подобрав правильно таймауты, кол-во одновременных запросов и плюс очередь из промисов — можно получить конкурентный вариант, но из коробки судя по всему такого нет для текущей задачи. (Хотя именно amp-параллелизацию я не раз использовала и в необъемных тасках она себя показывает очень неплохо, и так же достаточно легко внедряется)

Результаты: В первую очередь надо иметь в виду, что цифры не очень показательны сами по себе, многое зависит от сети и скорости интернета. Я запускала в докере, прилагаемом к репе и так же на незагруженном сервере. Цифры отличались, но расклад в целом не поменялся. Поначалу результаты ReactPhp меня очень удивили, потому что он бессовестно сливал. Но при увеличении количества запросов и стал показывать себя гораздо лучше. Если количество запросов порядка нескольких тысяч и более — однозначно стоит посмотреть в сторону реакта, но каких-то космических преимуществ я пока не увидела. (Возможно мне за это в личку напишут специалисты и натыкают носом, и я обязательно добавлю исправления, но пока расклад такой..) Ну а Guzzle в целом показывает себя очень достойно.

В планах еще потестить с записью в базу с асинхронными клиентами, но это чуть позже…

UPD: Дмитрий Балабка предложил свою идею улучшения Amp -клиента на основе очереди SplQueue, к сожалению — это совсем не решило проблем с производительностью

UPD2: К нам подключился один из разработчиков Amp, Niklas Keller, пофиксил баг и показал своё профессиональное решение задачи. Оказывается, решение для построчного чтения файла в Amphp всё-таки есть!

Так что, благодаря усилиям Дмитрия и Никласа, производительность Amphp реабилитирована, скоро обновлю статистику.

UPD3: Итак, аутсайдер вырвался в лидеры! Обновленные измерения показывают преимущества amphp независимо от количества запросов.

UPD4: В ближайшее время в репозиторий amphp будет добавлен класс для упрощения организации очереди запросов, а так же примеры его использования https://github.com/amphp/sync/pull/15

UPD5: Да! Команда ReactPHP не осталась в стороне:

--

--

Insolita

#php,#yii,#laravel,#javascript, #python,#linux,#archlinux,#vue