Search
Write a publication
Pull to refresh

Comments 21

Спасибо за отклики! Будет больше — обязательно напишу про POST запросы и работу с куками.
UFO landed and left these words here
Готово. Сразу не знал просто, как ее сделать…
UFO landed and left these words here
Первый блин частенько комом бывает. Тем более когда не всё очевидно как делать. Впредь постараюсь сразу нормально выкладывать.
Браво — велосипед едет :) Потом обернете в класс. А вообще маленькая подсказочка как работать с неблокируемыми сокетами и не тратить времние на днс лукап и прочее.
Запускаете 100 неблокируемых коннектов в 2 процессах (т.е. тупо по писят) первый процесс собирает айпшники для доменов, второй коннектится собственно к доменам по айпи. В такой модели у вас никогда не будет простоя, даже если хост не найден (т.к. gethostbyname() пользуется вродебы системным таймаутом а на жестко задаваемый плевать хотел.)
Ну, по порядку.
Первое, в класс я лично оборачивать и не собираюсь — реальное применение этого кода значительно сложнее приведенного примера, и там не так просто (да и смысла нет) делать класс. Кто хочет, может, конечно, «обернуть».
Второе, пример сделан на cURL, а libcurl блокирующая (асинхронно только через обертку конкретного ЯП). Сам же PHP нити не поддерживает, насколько мне известно.
Третье, таймаут gethostbyname() задаётся socket_set_timeout(). По крайней мере так написано на php.net. ( Самы сокеты в PHP применял редко, обычно на асме их, так что на тонкостях таймаутов настаивать не могу. )
Четвертое, много доменов имеют очень большие временные задержки между отправкой запроса и приходом ответа. Иногда до 10-20 секунд. Соответственно, время затрачиваемое на DNS lookup роли вообще практически не играет.
Велосипед то он велосипед, но!
очень уж он часто востребованный велосипед. Слишком многим не хватает в php тридов…

PS: раньше писал на перл, потом присел на пхп для повседневных задач. в итоге когда столкнулся с подобной проблемой делал на пхп велосипед тоже, хотя знал что это можно сделать _правильнее_ на перл, но на пхп както проще и быстрее сделать… странно да?
Вот и я в Web начинал с Перла. А на PHP пересел лишь потому, что с ним больше охват поддерживаемых хостингов и выше спрос на задачи. Вот теперь в основном на нем для Web и пишу.

Посмотрим еще, как на продолжение отзывы будут. POST, управление печеньками и еще по мелочи…
Не хотел бы получить минусов, как это часто бывает на Хабре, ибо он не жалует какое-либо обучение, что расстраивает, но все же: Чем классы удобнее функций? Наверное легче воспользоваться одной функцией, просто передав в нее массив параметров, чем взять объемный класс, который даже непонятно как подключить, а ведь еще и использовать надо… А тем более, когда одну функцию умудряются обернуть в библиотеку :/
Разные задачи, разный подход, если что-то мелкое, то и функции достаточно, если долгоиграющий проект с постоянно поддержкой, лучше классами обходиться. Причин может быть много.

P.S.
Минусов не получишь, потому что статья 2009 года, в старых статьях минусы сложно получить.
Ах да, и правда, статья старая…

Согласен, при разработке крупных проектов, особенно которые будут поддерживаться разными программистами, классы оказываются очень удобными и подчас незаменимыми. Просто для всего свое применение. Вот я и ратую за то (особенно этим часто грешат начинающие программисты), когда их используют по сути не по назначению, и часто самому приходится упрощать его, удаляя все конструкторы и методы, и получая в итоге из увесистой библиотеки одну функцию. Ну максимум две) Вторая — служебная для каких-нибудь внутренних преобразований. Например, тут — наглядный пример того, что можно обойтись одной простой функцией.
Во многом вопрос привычки и единообразия стиля.
Вот прямо сейчас переписываю свой древний проект (времен пхп4) под новое окружение. Я как-то даже не задумывался — а зачем собственно я эти библиотеку в класс завернул?.. Сразу завернул и всё. Равно как не думал о том что более кошерно будет делать синглтон чем тупо всё статикой делать.
Сейчас задумался. Первое что приходит в голову — а как я ее подгружать буду? Жестко инклюдом? Добавлю эти функции в файлик шорткатсов где у меня лежат все функции? Писать какую-то автозагрузку для библиотек? Вне зависимости от того каким путем идти я потрачу на это больше времени чем завернув в класс — заворачивая в класс просто кодишь, не думая. Разве что я задумался о том куда класс ложить — в хелперы или компоненты. Ну ок, пойду я против течения сделаю таки функцией. И потом кто-то возьмет проект на поддержку вместо меня (а это одна из целей рефакторинга — отвязать поддержку от меня). Он потратит какое-то время чтобы найти эти функции. Нет умный ИДЕ конечно поможет. Но лично я обычно по старинке лезу в тот файл что ожидаю, а уж если не получилось то ищу или тыкаю «показать объявление» или что-то вроде… А так в принципе то класс и на класс не тянет — один публичный метод, два приватных (именно приватных, я не буду от этого класса наследоваться, я его полностью переписывать буду потом).

Ну а вообще да, мысль забавная. Бывает действительно берем старые библиотеки, делаем из них классы, налепляем синглтонов и прочего, а потом когда часто используем — делаем функции в шорткатсах которые вызывают наши классы)
Вставлю и свои 5 копеек, если можно.

В приведенном примере используется переменная "$ghandler", но она не объявлена. Ее следует заменить на $mh, тогда пример будет работать «из коробки».

И да, было бы круто, если бы вы это оформили в виде класса ;) и залили куда то на гитхаб какой то ;)

Спасибо за статью.
И еще… там где echo вставляются вот такие кавычки «» — они соответственно не поддерживаются в php :(
Было бы удобней если бы для echo использовались обычные одинарные или двойные.
Кавычки в оригинале и были «нормальными», это уже перемены на Хабре за эти годы привели к такому виду кода.
С $ghandler согласен, уже и не помню, почему он в примере встретился.

А насчет github… Этот код сейчас видится настолько простым и очевидным, что выкладывать его как-то не серьезно прямо. Даже с допилками, которые с ним происходили за несколько лет.
Попробовал в деле коробочную версию скрипта… ну почти хорошо. Если коллбек выполняется не мгновенно, то возникнут проблемы. Допустим у вас 10 страниц каждая парсится по 1 секунде (время выполнения коллбека), а мультикурл загружает все страницы за 3 секунды, тогда коробочный скрипт отпарсит лишь 3 страницы, Если хорошенько подумать, то можно понять почему. Главный цикл заканчивается, когда всё страницы загружены, но не факт, что все распарсены.

Чтобы этого избежать нужно вместо:
if ( $running != $prev_running ) {
    $info = curl_multi_info_read( $mh );
    ...
}

написать следующее:
do {
    $info = curl_multi_info_read( $mh );
    ...
} while ($info);

Переменную $prev_running удалить.
При запуске скрипт выдает ошибку. В коде походу все еще ошибка. Здесь
 $info = curl_multi_info_read( $ghandler );

вместо $ghandler должно быть $mh
Еще два момента.
Данный скрипт может пропускать заданные юрлы. Фишка в том, что curl_multi_info_read( $mh) возвращает последнее сообщение, но в очереди могут остаться еще сообщения.
Ну и насчет цикла без пауз до окончания загрузки всех страниц — это излишняя нагрузка на процессор.

Здесь my_callback надо обернуть в кавычки:

var_export( http_load( $urls, my_callback ) );

Нужно отключить проверку SSL-сертификата, иначе при чтении по https вываливается ошибка #60 SSL certificate problem: unable to get local issuer certificate

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

Sign up to leave a comment.

Articles