Архитектура сетевего приложения.
От: Konstantin  
Дата: 12.11.14 20:17
Оценка:
Добрый день.

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

Есть некий логический блок, в который поступает команда. Например, скачать файл по FTP по этому адресу. Далее, после скачки и разбора содержимого, сделать следующие действия: либо записать содержимое в файл, лиюо модифицировать базу даных или ничего не делать. А также на основе содержимого этого файла запустить еще одно задание на скачивание. Ну и естественно, желательно чтобы это было распараллелино, чтобы скачивание было в несколько потоков, а запись в бд или в файлы тоже в отдельных потоках или как-то так.

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

Как бы это сделал я (тупо в лоб) для этой задачи:

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

Но я хотел бы идти ногу с модой Что хочется: асинхронную скачку, потому что не надо создавать треды на каждый коннект, плюс запиь в файлы и БД тоже отдельно в потоке сделать. Если файлы разные, то лучше каждый поток на отдельный файл. Обратил внимание на существование boost.asio. Никогда не программил ничего под бустом, тем более под его асинхронную библиотеку. Но смотрю все хвалят Для меня буст, а тем более asio выглядит как китайская грамота, но заоодно хочу изучить библиотеку.

Посоветуйте какая должна быть грамотная архитектура, чтобы все вышеперечисленные условия выполнялись. Если есть ссылки на конкретные примеры, то было бы вообще замечательно.
Re: Архитектура сетевего приложения.
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 13.11.14 10:27
Оценка: +1
Здравствуйте, Konstantin, Вы писали:

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

TaskQueue и производитель/потребитель. Идея простая, пока очередь пуста — процесс спит, как только пришло задание плановщик запускает поток или берёт его из пула и передаёт туда задачу. После завершения потоком работы он кладёт в очередь результат, палновщик уведомляется о том, что очередь не пуста и запускает снова поток на обработку. И так до бесконечности. Производители в этом случае потоки, а потребитель плановщик.
Sic luceat lux!
Re[2]: Архитектура сетевего приложения.
От: Sashaka Россия  
Дата: 13.11.14 10:46
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, Konstantin, Вы писали:


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

K>TaskQueue и производитель/потребитель. Идея простая, пока очередь пуста — процесс спит, как только пришло задание плановщик запускает поток или берёт его из пула и передаёт туда задачу. После завершения потоком работы он кладёт в очередь результат, палновщик уведомляется о том, что очередь не пуста и запускает снова поток на обработку. И так до бесконечности. Производители в этом случае потоки, а потребитель плановщик.

+1. Вместо самопальной TaskQueue можно использовать boost::asio::io_service + thread pool, примерно, так
Re[3]: Архитектура сетевего приложения.
От: Konstantin  
Дата: 14.11.14 09:25
Оценка:
Здравствуйте, Sashaka, Вы писали:

S>+1. Вместо самопальной TaskQueue можно использовать boost::asio::io_service + thread pool, примерно, так


Окей. Давайте, как говорится, "плясать от печки"

У нас есть главный поток приложения, в котором мы создаем класс, который отвечает за очередь команд. Предположим что-то типа FIFO стека.
Когда юзер нажимает на кнопу старт (к примеру) мы в эту очередь добавляем задание с параметрами. Предположим, что очередь сделана на основе io_service + thread pool. Тогда мы создаем число тредов, равное числу ядер процессора для оптимума. Обработчик очереди извлекает задания из очереди... И... ? Например, если это задание "записать в файл" или в БД, то понятно что можно его там и выполнить. А если это задание "скачать файл" ? То гда ведь надо еще какую-то очередь на скачивание иметь с тредами и потом оттуда по завершении сообщать результат... Или как быть? Вот тут не совсем понятен вопрос.
Re[4]: Архитектура сетевего приложения.
От: . Великобритания  
Дата: 14.11.14 09:38
Оценка:
Здравствуйте, Konstantin, Вы писали:

K>У нас есть главный поток приложения, в котором мы создаем класс, который отвечает за очередь команд. Предположим что-то типа FIFO стека.

K>Когда юзер нажимает на кнопу старт (к примеру) мы в эту очередь добавляем задание с параметрами. Предположим, что очередь сделана на основе io_service + thread pool. Тогда мы создаем число тредов, равное числу ядер процессора для оптимума. Обработчик очереди извлекает задания из очереди... И... ? Например, если это задание "записать в файл" или в БД, то понятно что можно его там и выполнить. А если это задание "скачать файл" ? То гда ведь надо еще какую-то очередь на скачивание иметь с тредами и потом оттуда по завершении сообщать результат... Или как быть? Вот тут не совсем понятен вопрос.
Число тредов по числу ядер это если все треды будут занимать процессор, т.е. вычисления, а не ввод-вывод (запись в файл, бд, скачка).
Поэтому можно в простом случае и одну очередь иметь c бОльшим числов тредов-обработчиков. Но таки да, для приоритетов, управлением параллелизации можно завести несколько очередей.
Сообщать результат никуда не надо, просто в ту же очередь (или очередь команд UI) класть задание "нарисовать диалог с ответом".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: Архитектура сетевего приложения.
От: Konstantin  
Дата: 14.11.14 09:46
Оценка:
Здравствуйте, ., Вы писали:

.>Здравствуйте, Konstantin, Вы писали:


K>>У нас есть главный поток приложения, в котором мы создаем класс, который отвечает за очередь команд. Предположим что-то типа FIFO стека.

K>>Когда юзер нажимает на кнопу старт (к примеру) мы в эту очередь добавляем задание с параметрами. Предположим, что очередь сделана на основе io_service + thread pool. Тогда мы создаем число тредов, равное числу ядер процессора для оптимума. Обработчик очереди извлекает задания из очереди... И... ? Например, если это задание "записать в файл" или в БД, то понятно что можно его там и выполнить. А если это задание "скачать файл" ? То гда ведь надо еще какую-то очередь на скачивание иметь с тредами и потом оттуда по завершении сообщать результат... Или как быть? Вот тут не совсем понятен вопрос.
.>Число тредов по числу ядер это если все треды будут занимать процессор, т.е. вычисления, а не ввод-вывод (запись в файл, бд, скачка).
.>Поэтому можно в простом случае и одну очередь иметь c бОльшим числов тредов-обработчиков. Но таки да, для приоритетов, управлением параллелизации можно завести несколько очередей.
.>Сообщать результат никуда не надо, просто в ту же очередь (или очередь команд UI) класть задание "нарисовать диалог с ответом".

Приоритеты не важны. Пускай все выполняется по очереди. Но предположим, если у нас будет один io_service, то может возникнуть такая ситуация: (если взять за основу пример гуглбота) Скачали страницу, а на ней 10000 ссылок. То есть одно задание на скачку породило 10000 заданий на скачивание. Для одного io_service я бы сказал, что это не хорошо, потому что во-первых цикл select/epoll будет тормозить, да и хотелось бы ограничить число одновременных коннектов.
Re[6]: Архитектура сетевего приложения.
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 14.11.14 10:18
Оценка:
Здравствуйте, Konstantin, Вы писали:

K>Приоритеты не важны. Пускай все выполняется по очереди. Но предположим, если у нас будет один io_service, то может возникнуть такая ситуация: (если взять за основу пример гуглбота) Скачали страницу, а на ней 10000 ссылок. То есть одно задание на скачку породило 10000 заданий на скачивание. Для одного io_service я бы сказал, что это не хорошо, потому что во-первых цикл select/epoll будет тормозить, да и хотелось бы ограничить число одновременных коннектов.

Скедулер решает сколько максимум можно запускать задач на исполнение, остальные задачи просто сидят в очереди и ждут пока освободятся ресурсы. Остальное работает как описал ".".
Sic luceat lux!
Отредактировано 14.11.2014 10:19 Kernan . Предыдущая версия .
Re[7]: Архитектура сетевего приложения.
От: Konstantin  
Дата: 15.11.14 09:50
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, Konstantin, Вы писали:


K>>Приоритеты не важны. Пускай все выполняется по очереди. Но предположим, если у нас будет один io_service, то может возникнуть такая ситуация: (если взять за основу пример гуглбота) Скачали страницу, а на ней 10000 ссылок. То есть одно задание на скачку породило 10000 заданий на скачивание. Для одного io_service я бы сказал, что это не хорошо, потому что во-первых цикл select/epoll будет тормозить, да и хотелось бы ограничить число одновременных коннектов.

K>Скедулер решает сколько максимум можно запускать задач на исполнение, остальные задачи просто сидят в очереди и ждут пока освободятся ресурсы. Остальное работает как описал ".".

Вы имеете в в виду вот такую конструкцию:
io_service service_;
ip::tcp::socket sock1(service_);
ip::tcp::socket sock2(service_);
sock1.async_connect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service_, boost::posix_time::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 5; ++i)
    boost::thread( run_service);
void run_service() 
{
    service_.run();
}


То есть у нас один io_service, но несколько тредов на обработку?
Re[4]: Архитектура сетевего приложения.
От: BulatZiganshin  
Дата: 22.11.14 23:25
Оценка:
Здравствуйте, Konstantin, Вы писали:

K> А если это задание "скачать файл" ? То гда ведь надо еще какую-то очередь на скачивание иметь с тредами и потом оттуда по завершении сообщать результат... Или как быть? Вот тут не совсем понятен вопрос.


грубо говоря есть два подхода — 1) создать кучу потоков ОС и пусть она сам с ними мутузится, 2) использовать асинхронный ввод/вывод, например libev или boost::asio (или вообще сделать задачу на хаскеле/ерланге, там это встроено в рантайм)
Люди, я люблю вас! Будьте бдительны!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.