| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > PHP: Для профи > Multi cURL, xmlsitemap, постоянный рост RAM |
| Автор: Psytodelist 6.5.2012, 22:09 | ||
Здравствуйте! Есть класс для создания xml-карты сайта:
При сканировании ссылок больших сайтов, скрипт упирается в memory_limit, в этот момент приблизительно выходит спарсено около 5000 ссылок (128М), увеличил до (500М) - 21000 ссылок. Когда я пользовался простым curl, парсил большие каталоги, то подобного постоянного роста RAM я не замечал. Данные заносились в БД. Тут же мы видем, что данные сохраняются в переменной. Именно это вызывает рост потребляемой оперативной памяти или что-то другое? Посоветуйте, пожалуйста, как оптимизировать данный класс. Благодарю. |
| Автор: Wolf1994 7.5.2012, 11:41 | ||
Размер ссылки почти всегда не больше четверти килобайта. 21000 / 4 = 5 Мб. Ошибка в том, что скрипт обрабатывает новые ссылки, не закончив обработку уже имеющихся. То есть, одновременно создаёт очень много запросов через cURL. |
| Автор: Wolf1994 7.5.2012, 11:59 | ||||
Решение.
multi_curl($new_links); вызывать после каждого выполнения multi_curl (), при условии, что массив не пустой, очищая $new_links перед обращением:
|
| Автор: Psytodelist 7.5.2012, 12:42 | ||||||||||||||||||||
- это вообще вызывается по завершении программы, идет форматирование массива ссылок в XML
Что именно записывать в переменную? Зачем? Это счетчик для AJAX, чтобы видеть прогресс в реальном времени. Забыл дописать WHERE uniqid='$uniqid' , но это не страшно. Добавлено через 2 минуты и 8 секунд
Спасибо хоть за попытку помочь, а-то гуры-партизаны или их вообще тут нет. |
| Автор: Fortop 7.5.2012, 13:07 |
| Psytodelist, лень Проблема собственно в том, что не очищается какая-то из переменных в процессе циклов. А искать ее желания нет Попробуйте делать unset объектам связанным с запросами после каждых 5000 (или сколько у вас там) ссылок. |
| Автор: Wolf1994 7.5.2012, 14:28 | ||
Потому и зачеркнул ответ (надо было стереть, наверно). 21000 UPDATE'ов не займут памяти, но немного (в зависимости от "железа" и типа таблицы) нагрузят систему без особой на то необходимости (для AJAX'а хватит и записи в файл и не на каждой итерации).
Вопрос не имеет отношения к уровню владения языком, а связан с алгоритмом, который создаёт многоуровневую параллельную обработку, вместо последовательной. Имел в виду, что не знаю, как пересоздавать массив при объектно-ориентированном стиле. |
| Автор: Psytodelist 7.5.2012, 16:47 |
| Wolf1994, я приблизительно понял в чем причина. Проштудировал весь код memory_get_usage() и выяснил, что память занимают переменные, которые получают результат от curl_exec() и curl_multi_exec() . Т.е. переменные $page = curl_exec($curl); и $multi_curl = curl_multi_exec($multi_curl_handler, $active); А это - целые страницы... Теперь попробую как-то это дело исправить. |
| Автор: Wolf1994 7.5.2012, 17:05 | ||
Да, из-за того, что каждая ссылка ведёт к созданию новых cURL запросов, которые создают под-запросы и так до бесконечности (в зависимости от структуры сайта и количества ссылок) - поэтому выделятся память под всё это и на стороне cURL и на PHP: под переменные, которые получают по нему страницы. |
| Автор: Psytodelist 7.5.2012, 17:16 | ||||
Походу ему все-равно на то, что я поставил unset-ы curl_multi_close($multi_curl_handler); unset($multi_curl, $content); $this->parse_content($page); unset($page); |
| Автор: Wolf1994 7.5.2012, 17:42 |
Потому что unset'ы срабатывают после вложенного запроса. То есть, $content через $this->parse_content($content); сначала передаётся в функцию parse_content, которая снова обращается к функции multi_curl и только по возвращению из последней происходит unset переданной переменной. |
| Автор: Psytodelist 7.5.2012, 17:45 | ||
Ага, точно. Исправить это надежды нет? Добавлено через 4 минуты и 53 секунды strlen-ом проверил переменную $content. Именно она, зараза, кушает оперативку. И как её ансетить при устовии многопоточной рекурсии, если можно это так назвать, я не знаю |
| Автор: Psytodelist 7.5.2012, 18:03 |
| unset($page); в конце скрипта - помогает, а unset($content); - нет unset($page); удаляет самое первое обращение к странице посредством простого курла. А когда я пишу unset($content); он не поймет же. Или поймет и-то в том цикле и-то если успеет закончится рекурсия. |
| Автор: Wolf1994 7.5.2012, 18:19 | ||||||
Есть, изменив параллельную работу на последовательную. Не проверял, но логику можно понять. Ключевые изменения:
|
| Автор: Psytodelist 7.5.2012, 18:21 | ||
в конце $this->parse_content() unset($GLOBALS['content'][$uniqcontentid]); не помогло |
| Автор: Psytodelist 7.5.2012, 18:36 |
| Wolf1994, привел Ваш вариант в ООП-шный вид, не работает. Пойду спрашивать на зарубежные сайты. Благодарю за помощь. |
| Автор: Wolf1994 7.5.2012, 18:42 | ||
Попробуйте на всякий случай в том виде, как есть. Вроде, ничего менять не надо. Добавлено через 4 минуты и 27 секунд Ошибся. Нужно сбрасывать счётчик $new_links_i; до добавления новых ссылок:
|
| Автор: Psytodelist 7.5.2012, 19:10 |
| Wolf1994, обращение к методам и свойствам происходит через this-> Опубликовал вопросец. Будем наблюдать что напишут. http://stackoverflow.com/questions/10485318/php-multi-curl-for-xml-sitemap-class-how-to-unset-recursive-content-variable |
| Автор: Wolf1994 7.5.2012, 19:23 | ||
Тогда так:
+ сброс счётчика в подходящем месте. |
| Автор: Psytodelist 7.5.2012, 19:27 | ||||||
Лучше уж так
Добавлено через 3 минуты и 13 секунд Инглишмэны не отзывчивые какие-то. Пойду посплю, может, прозрение настанет какое и Ваш вариант попробую. Благодарю за внимание |
| Автор: Wolf1994 7.5.2012, 19:33 | ||||
Так ещё лучше:
В алгоритме ошибок не вижу. Если поправите эти опечатки, должно работать. Добавлено через 2 минуты и 19 секунд
|
| Автор: Psytodelist 7.5.2012, 19:39 |
| А есть перевести все на простой cURL, то же самое придется делать? Добавлено через 1 минуту Тоже самое будет походу. |
| Автор: Wolf1994 7.5.2012, 19:44 | ||
Иправил все опечатки. Попробуйте выполнить этот код:
|
| Автор: Psytodelist 7.5.2012, 19:45 | ||
| А без перевода параллельного на последовательное нельзя никак? Я ж вроде все толково с $GLOBALS написал... вместо переменной глобальный массив с уникальным идентификатором... Точно ведь должен знать, какой элемент массива ансетить. Причем скрипт работал отлично при этом варианте, но ситуация с ростом оперативной памяти была та же. Добавлено через 34 секунды Ок, сейчас попробую просто скопировать и запустить. Добавлено через 5 минут и 17 секунд
те же результаты, только чуть хуже, потому что в этом варианте нет ансета $page походу |
| Автор: Wolf1994 7.5.2012, 20:07 | ||
Если много ссылок, то остаётся разбить один cURL_multi на несколько запросов с небольшим количеством URL'ов. Добавлено через 1 минуту и 6 секунд Пример выше - только для теста. |
| Автор: Wolf1994 7.5.2012, 20:22 | ||
Так правильнее:
- сработает при первых проходах на небольших количествах ссылок. |
| Автор: Wolf1994 8.5.2012, 06:58 | ||
Если меньше запросов в cURL_multi уменьшили потреление RAM, то такой скрипт должен полностью решить проблему:
|