Пишем простой асинхронный парсер

Многие разработчики типового говнософта, ориентированного на работу с вебом, зачастую используют потоки для того, чтобы получить выигрыш в скорости. Данный подход, конечно, обладает своими плюсами, но все же не является оптимальным, например, с точки зрения потребляемых ресурсов системы (особенно когда речь идет о потребителях, любящих ставить сразу "тыщу потоков").
Альтернативным и общеизвестным способом ускорения работы софта является асинхронная модель, то есть модель, при которой все вызовы методов являются неблокирующими. В данной статье я рассмотрю простой пример, который будет использовать асинхронные веб-запросы.
В качестве примера будет написан парсер идентификаторов приложений с Android Market, который пригодится в готовящейся статье, посвященной добычи трафика с маркета. Для простоты будем использовать модуль AnyEvent, он упрощает реализацию асинхронной событийной модели. Итак, приступим.

Для начала прагмы, необходимые инклюды и переменные:

В целом код довольно небольшой, поэтому я не буду излишне фрагментировать его, а изложу основную часть одним куском и прокомментирую.

Теперь сравним вышеприведенный скрипт со скриптом, который выполняет ту же самую работу, но опирается на потоки. Вот код этого скрипта:

Скорость работы скриптов примерно одинакова, и там и там идет одновременное выполнение 15 веб-запросов, однако, если обратить внимание на потребляемую память и нагрузку на процессор, то мы увидим явное преимущество у первого скрипта. У меня количество потребляемой памяти для асинхронного варианта составляло ~ 12 мегабайт, а в случае с потоками оно увеличилось до ~ 53 мегабайт (хотя прожорливость perl + pthreads под win* - известная печалька).
Но даже если абстрагироваться от языка программирования и использовать WinAPI для работы с потоками, то можно увидеть, что при большом количестве потоков (конечно, ведь чем больше потоков, тем круче и быстрее (с) дефолт логика) нагрузка на процессор вырастет несоизмеримо по сравнению с асинхронной моделью.

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

Скрипты из статьи: скачать

Пишем простой асинхронный парсер: 17 комментариев

  1. >конечно, ведь чем больше потоков, тем круче и быстрее (с) дефолт логика
    Дефолт сарказм обладателя полуядерного ЦП

    1. Риточка, Вы не правы. Если Вы поставите 1000 потоков на четырехядерной машине, Вы уже увидите, что приличная часть процессорного времени расходуется на переключение их контекстов. Если речь идет о Windows и перле, то вы и 100 потоков с трудом поставите, так как у вас оперативной памяти несколько гигабайт отожрется при этом. А если Вы поддерживаете мысль "1000 потоков - это охуенно", то советуем Вам немного пересмотреть свою логику. Хотя, вероятно, Вы просто can't into asynchronous.

        1. Серьезные дядьки-спамеры по социалочкам голосуют за Windows из-за наличия кучи дешевых дедиков! Windows - выбор профессионала.

  2. Что-то я не понял, зачем вам тут (f)lock понадобился. Приложение однопоточное, в каждый момент времени у вас может выполняться только один колбэк. Вопрос: зачем блокировка (еще и двойная)?

  3. Добыча трафика с маркета, это что такое? Переманивание посетителей с маркета на какой-то свой сайт? Или раскрутка своего приложения на маркете?

  4. Kaimi, ты так ненавидишь быдло/говно кодеров, но почему ты сам сам активно занимаешься быдло/говно кодингом за деньги? Или это чисто прагматическая ненависть к конкурентам?

  5. А в C# теперь есть async/await, благодаря чему IO completion ports использовать так же удобно, как и потоки.

  6. Подскажите как можно использовать AnyEvent::Socket? На CPAN этот модуль есть, а Perl Packet Manager его не отображает для установки.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *