вторник, 17 июня 2008 г.

Потоки: Мир захватили струйки информации!!!

Здравствуйте, уважаемые.

Первой статьёй на новом месте хочу отметить новоселье.

Совсем недавно мне надо было обрабатывать информацию с сайта. Загружать страницы, извлекать из них список нужных записей. Я хотел бы сегодня уделить внимание важности потокового (имею ввиду не Thread, а Stream) подхода в любой задаче обработки данных.
Полная постановка задачи:
Из списка сайтов, на каждом информация расположена на нескольких страницах, необходимо извлечь ее и вывести пользователю.
Возможности системы: одновременная скачка страниц с разных сайтов.
Первоначально задача сходилась к тому, что у каждого сайта есть парсер, который последовательно обходит все нужные страницы, собирая информацию, после чего выдает результат запрашивающему.
Эти парсеры запускаются параллельно, т.е. разными потоками. Результаты работы потоков также складываются объединяются в список, он дальше выдается как результат.
Фактически трехзвенка.

Недостаток: надо ждать пока все данные будут готовы. Для этого может потребоваться достаточно времени, и мы можем потерять внимание пользователя.

Логичное решение этой ситуации — это выдавать результат постепенно, по мере готовности данных страницы от любого парсера. Если оставить всё как есть, то нам придется избавиться от класса, инкапсулирующего в себе параллельную обработку парсеров. Выпускать из ларца Пандоры
беды и горе — дело, конечно, смелое, но неблагоразумное.
На ум пришло кардинально изменить механизм обработки информации. Приходится вносить изменения в самый нижний уровень, а именно, в механизм обработки конкретной страницы. И вот он! Герой. Поток, во всём его величии и стати.
Алгоритм следующий: раньше мы добавляли данные в список и возращали его запрашивающему объекту, теперь мы не будем возвращать ничего, теперь мы будем писать в поток, предварительно благоразумно переданный обработчику страницы. Таким образом, теоретически, мы можем не дожидаться полной загрузки страницы, а обрабатывать содержимое по мере его поступления, если такое теоретически возможно, и сразу выплевывать извлеченную запись в поток.

Приблизительно это будет выглядеть так:
public class SitesCollectionHanlder {
public void process(List<SiteHandler> handlers) {
List<Thread> threads =
new ArrayList<Thread>();
for (final SiteHandler h : handlers) {
Thread t =
new Thread(new Runnable() {public void run() {h.process();}})
t.start();
threads.add(t);
}
for (Thread t : threads)
t.join();
}
}

public class PageHandler {
public void process(int page) {
Object o;
prepareData();
while((o = nextObject()) != null)
stream.write(o);
}
}

public class SiteHandler {
public void process(int pagesAmount) {
PageHandler handler =
new PageHandler(stream);
for (int i = 1; i <= pagesAmount; i++)
handler.process(i);
}

public void process() {
process(
100);
}
}

Комментариев нет: