Для моего приложения, сколько потоков будет оптимальным? - PullRequest
3 голосов
/ 08 марта 2009

У меня есть простой веб-сканер Python. Он использует SQLite для хранения своих выходных данных, а также для хранения очереди. Я хочу сделать сканер многопоточным, чтобы он мог сканировать несколько страниц одновременно. Я решил создать поток и запустить сразу несколько экземпляров класса, чтобы все они работали одновременно. Но вопрос в том, сколько я должен бежать одновременно? я должен придерживаться двух? могу я пойти выше? что будет разумным пределом для ряда потоков? Имейте в виду, что каждый поток выходит на веб-страницу, загружает html, выполняет несколько поисков по регулярному выражению, сохраняет информацию, которую находит в базе данных SQLite, а затем выталкивает следующий URL из очереди.

Ответы [ 7 ]

13 голосов
/ 08 марта 2009

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

Добавляйте столько, сколько хотите, до тех пор, пока производительность не начнет ухудшаться.

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

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

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

Так что на самом деле нет жесткого и быстрого ответа. Предполагая соединение 1-5 мегабит, я бы сказал, что вы можете без проблем иметь до 20-30 потоков.

7 голосов
/ 08 марта 2009

Я бы использовал один поток и витой либо с отложенным семафором, либо с кооператором задач, если у вас уже есть простой способ ввести произвольно длинный список URL.

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

3 голосов
/ 08 марта 2009

Ответ Клетуса - тот, который вам нужен.

Несколько человек предложили альтернативное решение с использованием асинхронного ввода-вывода, особенно глядя на Twisted. Если вы решите пойти по этому пути, другое решение будет pycurl , которое является тонкой оболочкой для libcurl, который является широко используемой библиотекой для передачи URL. На домашней странице PyCurl есть пример retriever-multi.py , показывающий, как извлекать несколько страниц параллельно, примерно в 120 строках кода.

3 голосов
/ 08 марта 2009

Обычно проще сделать несколько параллельных процессов. Просто используйте подпроцесс, чтобы создать столько Popens, сколько вы считаете необходимым для одновременной работы.

Там нет «оптимального» числа. Обычно, когда вы запускаете только один сканер, ваш компьютер тратит много времени на ожидание. Сколько? Трудно сказать.

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

Если вы наберете какое-то большее число, вы увидите, что общее истекшее время больше, потому что теперь есть больше дел, чем может справиться ваш ЦП. Таким образом, общий процесс занимает больше времени.

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

Думайте об этом так.

1 сканер выполняет свою работу за 1 минуту. 100 страниц, выполненных последовательно, могут занять 100 минут. 100 сканеров одновременно могут занять час. Допустим, 25 сканеров заканчивают работу за 50 минут.

Вы не знаете, что оптимально, пока не запустите различные комбинации и не сравните результаты.

1 голос
/ 08 марта 2009

Следует иметь в виду, что некоторые серверы могут интерпретировать слишком много одновременных запросов с того же IP-адреса, что и атака DoS, и прерывать соединения или возвращать страницы ошибок для запросов, которые в противном случае были бы успешными.

Так что было бы неплохо ограничить число одновременных запросов к одному и тому же серверу относительно небольшим числом (5 должно быть на безопасной стороне).

1 голос
/ 08 марта 2009

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

Так как он написан на Python (и называется "простым"), я собираюсь предположить, что вы не совсем заинтересованы в том, чтобы выжать каждую унцию производительности из всего этого. В этом случае я бы предложил просто запустить некоторые тесты в обычных условиях работы и посмотреть, как они работают. Я предполагаю, что 5-10, вероятно, разумно, но это полный удар в темноте.

Поскольку вы используете двухъядерный компьютер, я настоятельно рекомендую проверить модуль многопроцессорной обработки Python (в Python 2.6). Это позволит вам использовать несколько процессоров на вашем компьютере, что значительно повысит производительность.

0 голосов
/ 08 марта 2009

Threading не требуется в этом случае. Ваша программа связана с вводом / выводом , а не с процессором. Сетевая часть, вероятно, будет лучше выполнена с использованием select () на сокетах. Это уменьшает накладные расходы на создание и поддержание потоков. Я не использовал Twisted , но слышал, что он действительно хорошо поддерживает асинхронные сети . Это позволит вам указать URL-адреса, которые вы хотите загрузить, и зарегистрировать обратный вызов для каждого из них. Когда каждый загружен, вам будет вызван обратный вызов, и страница может быть обработана. Чтобы разрешить загрузку нескольких сайтов без ожидания обработки каждого из них, можно создать второй «рабочий» поток с очередью. Обратный вызов добавит содержимое сайта в очередь. «Рабочий» поток будет выполнять фактическую обработку.

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

Я бы использовал один или два потока - один для фактического сканирования, а другой (с очередью) для обработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...