Как быстрее скачать? - PullRequest
0 голосов
/ 06 ноября 2011

Какой самый быстрый способ загрузить источник веб-страницы в компонент заметки? Я использую компоненты Indy и HttpCli.

Проблема в том, что у меня есть список, заполненный более чем 100 сайтами, моя программа загружает источник в заметку и анализирует этот источник для mp3-файлов. Это что-то вроде программы поиска музыки Google; он использует запросы Google, чтобы упростить поиск в Google.

Я начал читать о потоках, которые приводят к моему вопросу: могу ли я создать экземпляр IdHttp в потоке с функцией синтаксического анализа и сказать ему, чтобы он анализировал половину сайтов в списке?

Таким образом, в основном, когда пользователь нажимает парсинг, основной поток должен сделать:

for i := 0 to listbox1.items.count div 2 do
    get and parse

, а другой поток должен сделать:

for i := form1.listbox1.items.count div 2 to form1.listbox1.items.count - 1 do
    get and parse.

, поэтому они добавят проанализированный контент к form1.listbox2 одновременно. Или, может быть, проще запустить два экземпляра IdHttp в основном потоке; один для первой половины сайтов и другой для второй?

Для этого: я должен использовать Indy или Synapse?

Ответы [ 3 ]

9 голосов
/ 06 ноября 2011

Я бы создал поток, который может читать один URL и обрабатывать его содержимое.Затем вы можете решить, сколько из этих потоков вы хотите запустить одновременно.Ваш компьютер разрешит довольно много подключений, поэтому, если эти 100 сайтов имеют разные имена хостов, запускать 10 или 20 одновременно не проблема.Слишком много это излишне, но слишком мало - пустая трата процессорного времени.

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

Потому что в настоящее время у вас есть другие проблемы.Во-первых, не нужно использовать компоненты VCL в потоке.Если вам нужна информация из списка в потоке, вам нужно будет использовать синхронизацию в потоке, чтобы сделать «безопасный» вызов основному потоку, или вам нужно будет передать необходимую информацию, прежде чем запускать поток.Последнее более эффективно, поскольку код, выполняемый с помощью Synchronize, фактически выполняется в главном потоке, что делает вашу многопоточность менее эффективной.

Но мое внимание на самом деле было обращено на первую строку: " загрузить источник веб-страницыв мемо-компонент".Не делай этого!Не загружайте эти результаты в памятку для обработки.Автоматическую обработку лучше всего выполнять в памяти, вне визуального контроля.Использование строк, потоков или даже списков строк для обработки текста намного быстрее, чем использование заметки.
Строковый список также имеет некоторые издержки, но он использует ту же конструкцию индексации строк (TMemoStrings, которая является свойством Lines Memo, и TStringList оба имеют одного и того же предка), так что если вы получили код, который используетиз этого будет довольно легко преобразовать это в TStringList.

5 голосов
/ 06 ноября 2011

Я бы посоветовал выполнить ВСЕ разбор в потоках, но основной поток вообще не выполняет разбор. Основной поток должен управлять только пользовательским интерфейсом. Не разбирайте HTML из TMemo, пусть каждый поток загружается в TStream или String, а затем анализируется напрямую. Используйте TIdSync или TIdNotify для отправки результатов анализа в пользовательский интерфейс для отображения (если важна скорость, используйте TIdNotify). Вовлечение компонентов пользовательского интерфейса в логику синтаксического анализа замедлит его.

4 голосов
/ 07 ноября 2011

Indy или Synapse готовы к многопоточности. Я бы порекомендовал использовать Synpase, который намного легче, чем Indy, и будет достаточно для ваших целей. Не забывайте о HTTP API , предоставляемых Microsoft.

Простая реализация:

  • Один поток на URI;
  • Каждый поток получает данные, используя одну HTTP-связь;
  • Затем каждый поток анализирует данные;
  • Затем используйте Synchronize для обновления интерфейса.

Возможно, мой любимый:

  • Определите максимальное количество используемых потоков (например, 8);
  • Каждый из этих потоков будет поддерживать удаленное соединение (это цель HTTP / 1.1 и может реально повлиять на скорость);
  • Все запросы извлекаются этими потоками один за другим - не назначайте предварительно URL-адреса потокам, а извлекайте новый URL-адрес из глобального списка, когда поток завершает его (каждый URL-адрес не всегда занимает одно и то же время);
  • Потоки могут ждать, пока любой другой URI не будет добавлен в глобальный список (с использованием Sleep(100) или семафора, например);
  • Затем проанализируйте и обновите пользовательский интерфейс в основном потоке графического интерфейса, используя выделенное сообщение GDI (WM_USER+...) - разбор будет быстрым IMHO (и помните, что обновление пользовательского интерфейса может быть медленным - взгляните на BeginUpdate-EndUpdate методы для экземпляр) - я обнаружил, что сообщение GDI (со связанными данными HTML) более эффективно, чем использование Synchronize, которое блокирует фоновый поток;
  • Другой вариант - выполнить синтаксический анализ в фоновом потоке, сразу после извлечения данных из его URI - возможно, оно того не стоит (только если ваш анализатор работает медленно), и вы можете столкнуться с проблемами многопоточности, если ваш анализатор / процессор данных не на 100% поточно-ориентированный.

Во-вторых, насколько популярны так называемые «менеджеры загрузки».

Когда вы работаете с многопоточностью, вам придется «защищать» свои общие ресурсы (списки, например). Используйте TCriticalSection для доступа к любому глобальному списку (например, списку URI) и снимите блокировку как можно скорее.

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

...