Комментарии 21
Спасибо за отклики! Будет больше — обязательно напишу про POST запросы и работу с куками.
+1
Сделайте пожалуйста подсветку кода.
+3
Браво — велосипед едет :) Потом обернете в класс. А вообще маленькая подсказочка как работать с неблокируемыми сокетами и не тратить времние на днс лукап и прочее.
Запускаете 100 неблокируемых коннектов в 2 процессах (т.е. тупо по писят) первый процесс собирает айпшники для доменов, второй коннектится собственно к доменам по айпи. В такой модели у вас никогда не будет простоя, даже если хост не найден (т.к. gethostbyname() пользуется вродебы системным таймаутом а на жестко задаваемый плевать хотел.)
Запускаете 100 неблокируемых коннектов в 2 процессах (т.е. тупо по писят) первый процесс собирает айпшники для доменов, второй коннектится собственно к доменам по айпи. В такой модели у вас никогда не будет простоя, даже если хост не найден (т.к. gethostbyname() пользуется вродебы системным таймаутом а на жестко задаваемый плевать хотел.)
0
Ну, по порядку.
Первое, в класс я лично оборачивать и не собираюсь — реальное применение этого кода значительно сложнее приведенного примера, и там не так просто (да и смысла нет) делать класс. Кто хочет, может, конечно, «обернуть».
Второе, пример сделан на cURL, а libcurl блокирующая (асинхронно только через обертку конкретного ЯП). Сам же PHP нити не поддерживает, насколько мне известно.
Третье, таймаут gethostbyname() задаётся socket_set_timeout(). По крайней мере так написано на php.net. ( Самы сокеты в PHP применял редко, обычно на асме их, так что на тонкостях таймаутов настаивать не могу. )
Четвертое, много доменов имеют очень большие временные задержки между отправкой запроса и приходом ответа. Иногда до 10-20 секунд. Соответственно, время затрачиваемое на DNS lookup роли вообще практически не играет.
Первое, в класс я лично оборачивать и не собираюсь — реальное применение этого кода значительно сложнее приведенного примера, и там не так просто (да и смысла нет) делать класс. Кто хочет, может, конечно, «обернуть».
Второе, пример сделан на cURL, а libcurl блокирующая (асинхронно только через обертку конкретного ЯП). Сам же PHP нити не поддерживает, насколько мне известно.
Третье, таймаут gethostbyname() задаётся socket_set_timeout(). По крайней мере так написано на php.net. ( Самы сокеты в PHP применял редко, обычно на асме их, так что на тонкостях таймаутов настаивать не могу. )
Четвертое, много доменов имеют очень большие временные задержки между отправкой запроса и приходом ответа. Иногда до 10-20 секунд. Соответственно, время затрачиваемое на DNS lookup роли вообще практически не играет.
0
Велосипед то он велосипед, но!
очень уж он часто востребованный велосипед. Слишком многим не хватает в php тридов…
PS: раньше писал на перл, потом присел на пхп для повседневных задач. в итоге когда столкнулся с подобной проблемой делал на пхп велосипед тоже, хотя знал что это можно сделать _правильнее_ на перл, но на пхп както проще и быстрее сделать… странно да?
очень уж он часто востребованный велосипед. Слишком многим не хватает в php тридов…
PS: раньше писал на перл, потом присел на пхп для повседневных задач. в итоге когда столкнулся с подобной проблемой делал на пхп велосипед тоже, хотя знал что это можно сделать _правильнее_ на перл, но на пхп както проще и быстрее сделать… странно да?
0
Не хотел бы получить минусов, как это часто бывает на Хабре, ибо он не жалует какое-либо обучение, что расстраивает, но все же: Чем классы удобнее функций? Наверное легче воспользоваться одной функцией, просто передав в нее массив параметров, чем взять объемный класс, который даже непонятно как подключить, а ведь еще и использовать надо… А тем более, когда одну функцию умудряются обернуть в библиотеку :/
0
Разные задачи, разный подход, если что-то мелкое, то и функции достаточно, если долгоиграющий проект с постоянно поддержкой, лучше классами обходиться. Причин может быть много.
P.S.
Минусов не получишь, потому что статья 2009 года, в старых статьях минусы сложно получить.
P.S.
Минусов не получишь, потому что статья 2009 года, в старых статьях минусы сложно получить.
0
Ах да, и правда, статья старая…
Согласен, при разработке крупных проектов, особенно которые будут поддерживаться разными программистами, классы оказываются очень удобными и подчас незаменимыми. Просто для всего свое применение. Вот я и ратую за то (особенно этим часто грешат начинающие программисты), когда их используют по сути не по назначению, и часто самому приходится упрощать его, удаляя все конструкторы и методы, и получая в итоге из увесистой библиотеки одну функцию. Ну максимум две) Вторая — служебная для каких-нибудь внутренних преобразований. Например, тут — наглядный пример того, что можно обойтись одной простой функцией.
Согласен, при разработке крупных проектов, особенно которые будут поддерживаться разными программистами, классы оказываются очень удобными и подчас незаменимыми. Просто для всего свое применение. Вот я и ратую за то (особенно этим часто грешат начинающие программисты), когда их используют по сути не по назначению, и часто самому приходится упрощать его, удаляя все конструкторы и методы, и получая в итоге из увесистой библиотеки одну функцию. Ну максимум две) Вторая — служебная для каких-нибудь внутренних преобразований. Например, тут — наглядный пример того, что можно обойтись одной простой функцией.
0
Во многом вопрос привычки и единообразия стиля.
Вот прямо сейчас переписываю свой древний проект (времен пхп4) под новое окружение. Я как-то даже не задумывался — а зачем собственно я эти библиотеку в класс завернул?.. Сразу завернул и всё. Равно как не думал о том что более кошерно будет делать синглтон чем тупо всё статикой делать.
Сейчас задумался. Первое что приходит в голову — а как я ее подгружать буду? Жестко инклюдом? Добавлю эти функции в файлик шорткатсов где у меня лежат все функции? Писать какую-то автозагрузку для библиотек? Вне зависимости от того каким путем идти я потрачу на это больше времени чем завернув в класс — заворачивая в класс просто кодишь, не думая. Разве что я задумался о том куда класс ложить — в хелперы или компоненты. Ну ок, пойду я против течения сделаю таки функцией. И потом кто-то возьмет проект на поддержку вместо меня (а это одна из целей рефакторинга — отвязать поддержку от меня). Он потратит какое-то время чтобы найти эти функции. Нет умный ИДЕ конечно поможет. Но лично я обычно по старинке лезу в тот файл что ожидаю, а уж если не получилось то ищу или тыкаю «показать объявление» или что-то вроде… А так в принципе то класс и на класс не тянет — один публичный метод, два приватных (именно приватных, я не буду от этого класса наследоваться, я его полностью переписывать буду потом).
Ну а вообще да, мысль забавная. Бывает действительно берем старые библиотеки, делаем из них классы, налепляем синглтонов и прочего, а потом когда часто используем — делаем функции в шорткатсах которые вызывают наши классы)
Вот прямо сейчас переписываю свой древний проект (времен пхп4) под новое окружение. Я как-то даже не задумывался — а зачем собственно я эти библиотеку в класс завернул?.. Сразу завернул и всё. Равно как не думал о том что более кошерно будет делать синглтон чем тупо всё статикой делать.
Сейчас задумался. Первое что приходит в голову — а как я ее подгружать буду? Жестко инклюдом? Добавлю эти функции в файлик шорткатсов где у меня лежат все функции? Писать какую-то автозагрузку для библиотек? Вне зависимости от того каким путем идти я потрачу на это больше времени чем завернув в класс — заворачивая в класс просто кодишь, не думая. Разве что я задумался о том куда класс ложить — в хелперы или компоненты. Ну ок, пойду я против течения сделаю таки функцией. И потом кто-то возьмет проект на поддержку вместо меня (а это одна из целей рефакторинга — отвязать поддержку от меня). Он потратит какое-то время чтобы найти эти функции. Нет умный ИДЕ конечно поможет. Но лично я обычно по старинке лезу в тот файл что ожидаю, а уж если не получилось то ищу или тыкаю «показать объявление» или что-то вроде… А так в принципе то класс и на класс не тянет — один публичный метод, два приватных (именно приватных, я не буду от этого класса наследоваться, я его полностью переписывать буду потом).
Ну а вообще да, мысль забавная. Бывает действительно берем старые библиотеки, делаем из них классы, налепляем синглтонов и прочего, а потом когда часто используем — делаем функции в шорткатсах которые вызывают наши классы)
0
Вставлю и свои 5 копеек, если можно.
В приведенном примере используется переменная "$ghandler", но она не объявлена. Ее следует заменить на $mh, тогда пример будет работать «из коробки».
И да, было бы круто, если бы вы это оформили в виде класса ;) и залили куда то на гитхаб какой то ;)
Спасибо за статью.
В приведенном примере используется переменная "$ghandler", но она не объявлена. Ее следует заменить на $mh, тогда пример будет работать «из коробки».
И да, было бы круто, если бы вы это оформили в виде класса ;) и залили куда то на гитхаб какой то ;)
Спасибо за статью.
0
И еще… там где echo вставляются вот такие кавычки «» — они соответственно не поддерживаются в php :(
Было бы удобней если бы для echo использовались обычные одинарные или двойные.
Было бы удобней если бы для echo использовались обычные одинарные или двойные.
0
Кавычки в оригинале и были «нормальными», это уже перемены на Хабре за эти годы привели к такому виду кода.
С $ghandler согласен, уже и не помню, почему он в примере встретился.
А насчет github… Этот код сейчас видится настолько простым и очевидным, что выкладывать его как-то не серьезно прямо. Даже с допилками, которые с ним происходили за несколько лет.
С $ghandler согласен, уже и не помню, почему он в примере встретился.
А насчет github… Этот код сейчас видится настолько простым и очевидным, что выкладывать его как-то не серьезно прямо. Даже с допилками, которые с ним происходили за несколько лет.
0
Попробовал в деле коробочную версию скрипта… ну почти хорошо. Если коллбек выполняется не мгновенно, то возникнут проблемы. Допустим у вас 10 страниц каждая парсится по 1 секунде (время выполнения коллбека), а мультикурл загружает все страницы за 3 секунды, тогда коробочный скрипт отпарсит лишь 3 страницы, Если хорошенько подумать, то можно понять почему. Главный цикл заканчивается, когда всё страницы загружены, но не факт, что все распарсены.
Чтобы этого избежать нужно вместо:
написать следующее:
Переменную $prev_running удалить.
Чтобы этого избежать нужно вместо:
if ( $running != $prev_running ) {
$info = curl_multi_info_read( $mh );
...
}
написать следующее:
do {
$info = curl_multi_info_read( $mh );
...
} while ($info);
Переменную $prev_running удалить.
0
При запуске скрипт выдает ошибку. В коде походу все еще ошибка. Здесь
вместо $ghandler должно быть $mh
Еще два момента.
Данный скрипт может пропускать заданные юрлы. Фишка в том, что curl_multi_info_read( $mh) возвращает последнее сообщение, но в очереди могут остаться еще сообщения.
Ну и насчет цикла без пауз до окончания загрузки всех страниц — это излишняя нагрузка на процессор.
$info = curl_multi_info_read( $ghandler );
вместо $ghandler должно быть $mh
Еще два момента.
Данный скрипт может пропускать заданные юрлы. Фишка в том, что curl_multi_info_read( $mh) возвращает последнее сообщение, но в очереди могут остаться еще сообщения.
Ну и насчет цикла без пауз до окончания загрузки всех страниц — это излишняя нагрузка на процессор.
0
Здесь 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);
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Многопоточное скачивание в cURL на PHP