LINUX.ORG.RU

[Blocking queue] Не много ли потоков?


0

1

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

Хорошая ли идея использовать следующее решение. На каждое соединение 3 потока и 2 блокирующие очереди. Приходят сообщения, их надо обработать и ответить. Каждое сообщение проходит приблизительно так.

сеть -> MessageReceiverThread -> MessagesQueue -> MessageHandlerThread -> MessageResponsesQueue -> MessageSenderThread -> сеть

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

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

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

Похожий проект был на .NET на Asynchronous IO. Все бы хорошо, только Thread Pool там был прибитый гвоздями внутри .NET и контроля за ним особо не было. И когда много обработчиков какого-то типа чего-то ждали, то не хватало места под, например, отправку сообщений. И, опа, новые треды тред пул не давал. Сейчас разбираюсь как это в Java. Надеюсь есть смысл.

Сколько тредов - много?

★★★★★
Ответ на: комментарий от dave

Но все равно повех .NET, а там Async IO чрезвычайно дубовый. Феерический висяк случается когда все обработчики на всех машинах решают что-то отправить. Все вместе делают write. Ну что в этом плохого? А плохого-то, что никто не делает read. Тред пул, который callbacks вызывает внутри .NET один. Вот он от большого количества соедениний как раз в этот момент решает больше тредов не давать. И они все дружно пытаются отправить и даже не думаю читать. Такой дружный тридцатимашинный сетевой deadlock. Так как такой расклад не вписывался в мое мировоззрение, то я не мог понять что же именно имеет ввиду Parallel Stacks в MSVS2010. Угробил 3 дня из моего прекрастного двадцатилетия.

Конечно все решается ручным управленем тредами, от дотнетовского AIO профита 0. От Java конечно профит есть, очень хорошо реализовали. Кроме одного момента. interestOp - implementation dependent. И в Linux самая странная имплементация. Его нужно юзать только в одном потоке иначе он зависает на блокировке. Тоесть вместо того чтобы в любом треде его установить, я должен поставить в какую-то структуру данных уведомление, а потом вручную разбудить select чтобы он прочитал уведомление выставил то, что надо. Не знаю насколько это scalable, может быть узким местом. Учитывая то, как я это сомнительно делаю. Пишу уведомление в Set, блокируя и разблокируя его. Потом пробуждаю select в диспетчерском потоке вызовом wakeUp. Он просыпается, блокирует множество, включает interestOps и чистит множество. Потом разблокирует и вызывает select опять. У меня есть громадная надежда что эти операции очень быстры, всего-то, флажки выставить, и потому не будут вызывать проблем. Но будить постоянно диспетчер после завершения КАЖДОГО чтения не очень хорошо. Когда система будет хоть как то готова, то погоняю профилировщиком чтобы спать спокойно.

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Осилил это

class Foo {

    Selector sel;    
    Object gate = new Object();

    void doDispatch() {
        :  
        sel.select();  
        :
        synchronized (gate) { /* do nothing */ }
    }

    void doRegister(SelectableChannel ch, int ops) {
        synchronizsed (gate) {
            sel.wakeup();
            ch.register(sel, ops);
        }
    }
}

И этот недостаток устранен

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

А если по-простому самому написать через wait и notify? Как я понимаю, нужно сохранить баланс по читателям и писателям. Так, за этим можно следить.

dave ★★★★★
()
Ответ на: комментарий от dave

Через Executors красивее, так как можно менять стратегию аллокации потоков. Можно фиксированно, можно динамически на рассуждение JVM. Но из трез разных ExecutionService, в отличии от .NET. Думаю что можно и свой написать.

Через wait и notify конечно можно, но какой профит кроме простоты, если я правильно понял что вы хотите? Это же всего навсего явный, написанный вручную тред-пул под немного другим соусом. Executors по-моему очень красивое решение, отличная абстракция.

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Тут я уже пас. Признаю, что в этом вопросе ты знаешь больше :)

dave ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.