Перейти к содержанию
    

Система, управляемая событиями и SST(super-simple tasker)

Сергей Борщ, это называется Partial Template Specialization. http://en.cppreference.com/w/cpp/language/..._specialization

Сначала обьявляется шаблон с аргументами - тип и int. При чем последний имеет дефолтный параметр 1. Этот шаблон в данном случаи пустой.

Затем этот шаблон специализируем, то есть указываем компилятору, что будет, если пользователь захочет инстанциировать шаблон с конкретными аргументами - то есть это тип TRet(TArgs...) - функция, лямбда или функциональный обьект. второй - тот же инт.

Но сама специализация тоже шаблон - с аргументами, при чем переменного количества(эта фишка доступа только в C++11, в старых плюсах этого нет) :)

Компилятор, увидев строки вида delegate<void(int,char)> подставит в TRet=void; Targs = int, char; size=1 (аргумент по умолчанию).

 

А если написать что-то типа delegate<int> или delegate<char, 2> - что тоже будет правильным, тк подходит под template<class T, int d_size=1> - тогда компилятор не найдет реализации шаблона(тк она у нас пустая) и со временем выдаст ошибку(или кучу ошибок:)

 

Это так, на пальцах. Более подробно - в спецификации С++ и на выше приведенной мной ссылке. Ну и естественно - тренировка.

 

Вот еще один примерчик по-проще. Это шаблон динамической очереди исполняемых обьектов(в том числе функций и лямбда-функций). Туда можно пихать такие обьекты любого размера. В delegate тоже можно, только там делегат имеет фиксированный размер, и если обьект в него не влезет - компилятор выдаст ошибку.

В очереди уже память используется более эффективно - выделяется столько ячеек(32-битных слов), сколько нужно для обьекта и проверка происходит в рантайме(потому и динамическая).

// Variable item size delegate FIFO **
template<class T> class VdelegateFIFO;

// main template
template<class ... TArgs>
class VdelegateFIFO<void(TArgs...)>{

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Особенно меня удивил JS конечно же. Вот уж не ожидал так не ожидал ) Я JS использовал только в Qt, там он часть QML для создания интерфейсов.

 

В принципе реализация делегата более-менее стандартная. Нагугливается довольно легко.

 

У меня единственное остаются вопросы по SST конечно... постараюсь вкратце описать всё это.

Для начала давайте определимся, что любой объект с состоянием(для простоты рассматриваем класс в ООП) это так или иначе и есть конечный автомат. Методы класса в данном случае действуют как события приводящие или не приводящие к изменению состояния. Т.е. я хочу подчеркнуть, что в реальном мире у объекта много точек входа для изменения состояния.

Чтобы состояние менялось атомарно и состояние менялось строго в соответствии с графом(алгоритмом) при вызове методов из разных потоков(т.е. упростим до понятия "одновременно") вводятся мьютексы, сериализирующие изменение состояния. Т.е. делая эти изменения последовательными не смотря на то, что запросы на изменение пришли "одновременно".

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

Просто хочу чтобы мы это поняли.

Пеоеходим к SST:

Первое и самое главное ограничение это необходимость редизайна задачи(объекта, конечного автомата) таким образом, чтобы при выделении процессорного времени она быстренько run to completion. Следовательно мы должны проектировать наш объект(конечный атомат) таким образом, чтобы все изменения в состоянии происходили строго из одной точки входа(функции, которую дёргает SST планировщик). И обязательно принять условие, что только планировщик будет вызывать эту функцию. Обоснуем: извместно, что в любой момент выполнение может быть прервано другой задачей(более приоритетной, но это щас не важно) и не дай Бог та другая задача сделает что-то(вызовет метод), что изменит состояние первой задачи, которая находится в процессе смены состояния! Выполнение то было прервано на пол пути, где-то посередине ребра графа состояний конечного автомата. Бог знает в каком месте.

Я правильно мыслю? Не слишком блокировочно и многопоточно? ;)

 

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

Мы вроде как экономим память и проц т.к. не переключаем полный контекст. Безусловно ДА.

Обратная сторона медали:

Мы приходим к жесточайшим ограничениям межзадачного взаимодействия! Единственная точка входа в задачу заставит нас сообщения для этой задачи хранить в очереди. Реализация такой очереди требует унификации всех сообщений(событий) системы или подсистемы. Таким образом интерфейс задачи(объекта) превращается не в привычный набор методов, а в набор сообщений которые можно посылать объекту.

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

 

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

 

По этим причинам SST это далеко не панацея, а хитрое название для давно и хорошо известного автоматного подхода https://ru.wikipedia.org/wiki/%D0%90%D0%B2%...%BD%D0%B8%D0%B5

способ сэкономить немного памяти/немного проца за счет немалых изменений в архитектуре системы.

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

 

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

Как видим на примере современных ОС в реальном мире побеждает симбиоз потоков и разделения времени с событиями(асинхронный IO тому пример).

На чем наверно можно и сделать окончательный вывод )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для начала давайте определимся, что любой объект с состоянием(для простоты рассматриваем класс в ООП) это так или иначе и есть конечный автомат.

Да. Тред, работающий на одноядерном процессоре - тоже конечный автомат, вернее не тред, а вся эта тредовая ОС :)

 

Чтобы состояние менялось атомарно и состояние менялось строго в соответствии с графом(алгоритмом) при вызове методов из разных потоков(т.е. упростим до понятия "одновременно") вводятся мьютексы, сериализирующие изменение состояния.

Потоков нет. Поток у нас один. Мютексов тоже ессно нет. Но есть приоритеты событий.

 

Первое и самое главное ограничение это необходимость редизайна задачи(объекта, конечного автомата) таким образом, чтобы при выделении процессорного времени она быстренько run to completion. Следовательно мы должны проектировать наш объект(конечный атомат) таким образом, чтобы все изменения в состоянии происходили строго из одной точки входа(функции, которую дёргает SST планировщик). И обязательно принять условие, что только планировщик будет вызывать эту функцию.

Этим занимается компилятор. Я не могу сам вызвать функцию-обработчик - компилятор мне этого не позволит.

И это не ограничение, это другой стиль программирования, и очень классный! ;)

 

Бог та другая задача сделает что-то(вызовет метод), что изменит состояние первой задачи, которая находится в процессе смены состояния! Выполнение то было прервано на пол пути, где-то посередине ребра графа состояний конечного автомата. Бог знает в каком месте.

Другим задачам запрещено менять состояние данной задачи. Любая коммуникация между задачами происходит через очереди(каналы, пайпы, fifo - называйте как хотите). Если задача А хочет изменить состояние задачи Б, тогда задача А ставит этот запрос в очередь, и как только задача Б будет готова принять эти изменения - она это сделает. Всем этим занимается не пользователь, а компилятор вместе с планировщиком.

 

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

У Вас для сериализации доступа используются тяжеленные мютексы и громадный стек, а у нас - легковесные быстрые очереди, довольно не редко lockfree.

 

Таким образом интерфейс задачи(объекта) превращается не в привычный набор методов, а в набор сообщений которые можно посылать объекту.

Да, но это не ограничение, а другой стиль. Зачем сделали NodeJS, если есть PHP, Python и другие динамические языки. Разве ради того, чтобы загонять программистов в ограничения? Да на Javascripte такое можно сделать, что Php-шнику или Питонщику не снилось, и работать это будет очень быстро.

 

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

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

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

Да и большинство задач юзера имеют одинаковый приоритет. С приоритетами надо поработать только с системными задачами - та же шина SPI, Uart, Dma, итд. Ну и естественно - с прерываниями, они тоже могут друг друга прерывать(вытеснять) :) У пользователя обычно всего 1-2-3 приоритета.

 

В системе появляется много функторов(делегаты ваши) которые циркулируют туда-сюда...

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

 

Для их применения вам придется делать обёртку либо каждый раз изобретать велосипед. О чем вам уже не только я говорил.

Часто готовый софт либо что-то делает одно(типа MP3, jpeg итд) и свободно ложится на SST. Либо имеет возможность работать в асинхронном неблокирующем стиле, хоть и через костыли (как, например Linux в отличии от FreeBSD). Но если софт жестко завязан на потоки и без них там никак - в мусорку этот софт. Например Апач - без PHP он бесполезный. А нафик PHP, если есть NodeJS? И нафиг тогда сервер(бесполезная прослойка), если на этом же Node такой сервер пишеться за 20 минут(на установку и настройку апача уйдет не меньше), а остальное время будет потрачено на бизнес-логику, которое могло быть потрачено на ту же логику на PHP? Значит втопку апач.

Точно так же и другой софт. Если там нет Async Nonblocking IO - дорога ему в мусорку, rm -rf * :)

 

По этим причинам SST это далеко не панацея, а хитрое название для давно и хорошо известного автоматного подхода https://ru.wikipedia.org/wiki/%D0%90%D0%B2%...%BD%D0%B8%D0%B5

способ сэкономить немного памяти/немного проца за счет немалых изменений в архитектуре системы.

Конечно это не панацея, и это автомат. Но довольно продвинутый, там кейсом не обойдешься, ибо простейшая задача будет иметь 100 и более кейсов :)

 

Как видим на примере современных ОС в реальном мире побеждает симбиоз потоков и разделения времени с событиями(асинхронный IO тому пример).

На чем наверно можно и сделать окончательный вывод )

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

 

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

Поэтому выход один - допиливать в существующие ОС async IO, планировку процессов оставлять в sync-стиле, а сами приложения проектировать в async-стиле. Да любая нормальная софтина сейчас в async-стиле делается, тот же Qt, Node итд итп.

 

За всю историю, сколько я пишу на QT, я создавал треды только тогда, когда надо было в фоне непрерывно, на всем доступном процессорном времени что-то считать, например FFT. Остальное IO свободно работало в главном потоке(там, где и GUI) и система работала шустро. FFT-поток получал данные через очередь, никаких мютексов - подключил свой велосипед под названием SPSC lock-free queue. Благо, у STL для этого есть atomic-переменные, и у Интела есть их аппаратная поддержка.

И то этот поток - вынужденная мера, тк в QT нет приоритетов событий. Если бы был приоритет - я бы просто поставил FFT приоритет ниже, чем в GUI и все, был бы абсолютно тот же эффект.

 

Гляньте на язык Java, вернее на приложения, которые на нем написаны. Как они тормозят. На любом железе тормозят жутко. Потому что там тонны потоков(хоть ява и позволяет программировать asnyc, особенно сейчас). И посмотрите, как летает однопоточный асинхронный Javascript в Node :)

 

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

Асинхронный подход позволяет решить любую задачу(равно, как и синхронный). Только это решение в 90-95% случаев лучше, красивее, эффективнее, чем на потоках. Примеров тому масса, они повсюду.

 

Или вот тот же мой сервак, который отправляет пользователю рандом 100 раз в секунду. Асинхронное решение простое, натуральное, и отправляет действительно строго каждые 10мс.

		var timer;
	function on_socket_closed(){
		n_connections--;
		clearInterval(timer);
	}

	// Periodically send random data to client
	timer = setInterval(function(){
		var str;
		for(var i=0; i<100; i++){
			str+= String.fromCharCode(Math.random()*256);
		}
		socket.write(str);
	}, 10);

 

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

	char buffer[4096];
int i,r;
while(1){
	for(i=0; i<100; i++)buffer[i] = rand();
	r = send(sock, buffer, 100, 0);
	if(r<=0){
		perror("Thread_connection: socket error");
		break;
	}
	usleep(10000);
};

Что бы было меньше джиттера, нам придется создать еще один поток - таймер, создать семафор, в таймере его устанавливать(инкрементировать) а в отправителе декрементировать. Жуть - 2 потока только ради того, чтобы периодически отправлять набор байт :(

А что будет, если будет реальная задача? Когда таймеров понадобится штук 5? Даже представить сложно, как это все будет тормозить и глючить...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати справедливости ради надо добавить, что идея именно посылать объекту сообщение идет еще со времен первых экспериментов с объектно ориентированным программированием.

Именно такая парадигма была принята в языке Smalltalk. Где-то, кажется у Фулера, читал что это типа тру ООП подход, позволяющий полностью инкапсулировать объект. Где-то там даже была критика С++, который жестко формализируя сигнатуру каждого метода как-бы выдает часть информации о себе, нарушая инкапсуляцию.

 

Из ныне живых(пока еще) языков, использующих для вызова метода именно посылку сообщения я могу припомнить Objective-C

компилируемый объектно-ориентированный язык программирования, используемый корпорацией Apple, построенный на основе языка Си и парадигм Smalltalk. В частности, объектная модель построена в стиле Smalltalk — то есть объектам посылаются сообщения. Язык Objective-C является надмножеством языка Си, поэтому Си-код полностью понятен компилятору Objective-C.
https://ru.wikipedia.org/wiki/Objective-C

 

Когда-то немного баловался приложеньками для айфона.

Может кому будет интересно почитать как они умудрились сделать такую веселую надстройку над Си

http://steps3d.narod.ru/tutorials/objective-c-tutorial.html искать главу Как работает механизм сообщений

 

Но использовать SST и один стек в реальном проекте для проца мощнее AVR я бы всё равно сейчас не стал ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Smalltalk прикольная штука, но не прижилась. Но там нет очередей, просто абстракция другая, неявных интерфейсов. Хотя и в Go они тоже неявные.

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

Немало кода(можно сказать - большинство) работает в обычном неблокирующем ОО стиле, как в Qt, например или том же JS. Сообщения начинаются там, где нужно работать с чем-то внешним по отношению к себе. Например, читать файл с флешки или температуру с DS18B20. Или тогда, когда надо делать тяжелые вычисления.

 

Но использовать SST и один стек в реальном проекте для проца мощнее AVR я бы всё равно сейчас не стал ))

Применяю однопоточный подход начиная с AVR и заканчивая многоядерными серверами. На многоядерных, правда стеков(и потоков) столько, сколько и ядер, но это не важно. Планировщик сам раскидывает события по нужным потокам(ядрам). Для меня все выглядит, как 1 поток.

Конечно, систему с нуля писать под эти серверы я не собираюсь, есть замечательные ОС в которых все уже сделано, в том числе и SST, только более навороченный.

Но под МК от 8 до 400 мгц и DSP/DSC от 50 до 700мгц с лихвой хватает своей простейшей SST-ос. А часто, на относительно простых проектах, даже и SST не нужен - достаточно того функционала, который дает железо(проц и контроллер прерываний) - пользовательский код крутится в одном самом низком приоритете, а системный - на всех остальных более высоких приоритетах, у каждого проца это количество свое - от двух до 256 и выше.

Многозадачность может спокойно быть и без ОС вообще. При чем код будет даже проще, чем с ОС(тем же SST) - тк всего один приоритет. Этого достаточно для рисования GUI, обработки всевозможных кнопочек и тачскринов, одновременно с этим читать файлы с карт памяти, контролировать температуру, заряжать батарею и много чего еще без всяких замираний и тормозов, система летает, как самолет на довольно простом МК.

Я даже не представляю, какой МК понадобился бы, если решить в многопоточном стиле те задачи, которые я на них запросто решаю в асинхронном однопоточном - с одним единственным стеком. Наверное пришлось бы брать простой PC + линукс(или какой-нибудь андроид) и не париться, только рентабельность такой системы будет никакая, равно как и энергопотребление бешеное.

 

Да и код монстроидальный и глючный выходит, невозможно писать нормальный код на мютексах + shared memory, очень много времени требуется на отладку. На сложных проектах рано или поздно запутаешься, да и мютексы не гарантируют отсутствие гонок(зато приносят кучу проблем) - вы можете наложить локи не в той последовательности или не на те данные и все - поведение программы будет зависеть не от вас, а от случая.. А гонки очень трудно вылавливать, даже имея специальный для этого софт. я уже проходил через это.

Зато очереди дают гарантию, что все отработает так, как надо. Приходится их применять и в многопоточном стиле(вместо мютексов, хотя сами очереди могут быть построены на мютесках, а могут и нет. Но все равно эти мютексы локализованы в одном месте - в коде очереди, а не разбросаны по всему проекту.

А когда в многопоточном ПО появляются очереди - вы уже на пол пути к однопоточному стилю. Со временем там появятся асинхронные таймеры, Active-objectы с приоритами, async nonblocking IO в конце концов, и все - вы программируете асинхронно, пора выкидывать вашу RTOS в мусорку, как ненужную прослойку(типа апача) :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

все - вы программируете асинхронно, пора выкидывать вашу RTOS в мусорку, как ненужную прослойку
Вот что мне не нравится - это ваша фанатичность ) Видимо молоды еще. Или темперамент такой )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ок, с фанатичностью убавим ;)

Мне тоже лень было, но таки переборол себя и выкинул, теперь доволен, хотя по началу было сложно, но деваться некуда - код и так со временем ставал практически асинхронным, редко где оставались блокирующие вызовы. Но был очень горбатым тк работал под синхронной ОС - гибрид такой получался, да и опыта мало было, пришлось на JS поработать, чтобы набраться. Потом я удалил ОС, и в месте с ней десятки тысяч строк кода и начал новые проекты делать вообще без ОС, и строил велосипеды так, чтобы чувствовать себя как можно ближе к JS. На некоторых проектах такого подхода не хватало(а РТОС взять религия не позволила) и тут я вспомнил, что где-то читал про какой-то там SST не обратив на него особого внимания, тк работал на нормальных РТОС. Нашел, разобрался и понял, что это именно то, что мне нужно. Еще месяца 4 практики и получился крутой фреймворк, убивающий по производительности и простоте кода любую RTOS. Как убивает Node любую синхронную систему, как по простоте кода(сервак можно написать парой тройкой строк), так и по скорости и памяти, хотя JS довольно тяжелый и медленный язык.

 

Вот сейчас мне тоже лень изучать Rust, все плюсами довольствуюсь. Не могу решиться найти время и силы на это, но вижу, что придется, а то все таки плюсы - опасный язык, хотя безопасность повышается использованием высоко-уровневых библиотек(STL), но с ними трудно работать на слабых МК до 50мгц/8кб, надо что-то подпилвать, что-то выпиливать, а это я не люблю, проще самому сварганить велосипед на сотню строк за пол часа (собственно так и было сделано).

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1000 потоков так и не смог создать - линукс падает намертво, приходится ресет жать. Кое как создает 400 потоков и сжирает всю память, комп жутко тормозит и выдает еле 600 коннектов в секунду

Каждый поток в линукс создается со стеком ~8Мб по умолчанию, вот память и кончается. Можно изменить pthread_attr_setstacksize

Но лучше все же для тестирования использовать стандартные инструменты, например http://httpd.apache.org/docs/2.2/programs/ab.html

Тут даже сравнивать нечего. Сервак на NodeJS убивает любой другой многопоточный, а тормознутого Апача десять раз убивает. Он может только конкурировать с серваком на Go, при одних задачах лучше NodeJS, при других - Go. Я работал и на том и на другом.

Видимо гуру не знает, что "Сервак на NodeJS" написан на основе libuv, например. А nodejs "в продакшене" прячут за тем же nginx...

 

А так, в принципе, можно договориться до того, чтобы запретить размещение обьектов в стеке средствами C++. Или использовать только реентерабельные функции и статические данные в С. Тогда никакого стека вообще не будет, и никакой кучи тоже.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Видимо гуру не знает, что "Сервак на NodeJS" написан на основе libuv, например. А nodejs "в продакшене" прячут за тем же nginx...
Ахахахаа. Вот это поворот.

А я и думаю чё за шайтан Javascript такой быстрый, а! У меня в Qt он чуть что не так - тормозить начинает.

Во думаю ребята движок V8 до чего допилили! А оказывается эта вся шайтан-машина только патроны в Сишный пулемет заряжает ))))))

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Каждый поток в линукс создается со стеком ~8Мб по умолчанию, вот память и кончается. Можно изменить pthread_attr_setstacksize

А потом в один прекрасный момент стека не хватит и Ваше приложение слетит. В однопоточном стиле такой опасности нет.

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

Кста посмотрел, стека у меня выделяeтся 2мб (ничего не менял). Итого получается, что 1000 потоков сожрали всю память и линукс сдох, помог только reset. Когда асинхронное приложение уперлось в какие-то лимиты или тормоза ядра и до полного использования ресурсов системы еще очень далеко, и при этом обрабатывала почти в 10 раз больше клиентов. Система нормально работала даже во время работы сервака и клиента, только сокет создать невозможно было. После отключения клиента все продолжало дальше работать без тормозов.

 

Видимо гуру не знает, что "Сервак на NodeJS" написан на основе libuv, например. А nodejs "в продакшене" прячут за тем же nginx...

Конечно я не знаю что там внутри, меня это не интересует, главное - результат. А Nginx - асинхронный, поэтому не удивительно.

 

А я и думаю чё за шайтан Javascript такой быстрый, а! У меня в Qt он чуть что не так - тормозить начинает.

Во думаю ребята движок V8 до чего допилили! А оказывается эта вся шайтан-машина только патроны в Сишный пулемет заряжает ))))))

Быстрый не JS, быстрая сама технология однопоточного асинхронного IO и программирования в целом. JS язык довольно медленный, для вычислений не годится.

Qt - асинхронный неблокирующий event-driven стиль. Будет где-то тяжелый цикл, блокирующий вызов или другой тупняк - будут жуткие тормоза.

Могу и на C сделать быстро асинхронно(и без libuv), скорее всего получится даже быстрее(или так же), чем Node. Тут рулит технология, а не язык или инструмент.

 

А так, в принципе, можно договориться до того, чтобы запретить размещение обьектов в стеке средствами C++.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Горбатый стиль работы с очередью (или сама очередь горбатая - гибрид):

queue.setOnReadyRead(readyRead);
....
void readyRead(){
   char buffer[1024];
   while(true){
       int len = queue.read(buffer,sizeof(buffer);
       if(len<=0)break;
       // process the data
       process(buffer, len);
    }
}

 

Нормальный асинхронный стиль:

queue.setReceiver(receiver);
....
void receiver(const char* data, size_t len){
   process(buffer, len);
   queue.signal_receiverCompleted(); // не обязательно, но иногда очень полезно
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кста посмотрел, стека у меня выделяeтся 2мб (ничего не менял). Итого получается, что 1000 потоков сожрали всю память и линукс сдох, помог только reset.

с точки зрения приведенного вами кода у вас странное представление о синхронности.

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

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

 

Т.е. для имитации синхронности по идее нужно было обрабатывать события на сокетах при помощи select, а не каждое соединение в своем отдельном потоке. В случае асинхронности использовать epoll

 

Кстати, современных "синхронных" серверов уже совсем не осталось. И "тормознутый апач" уже давно может epoll : http://httpd.apache.org/docs/2.4/mod/event.html

Вот в FAQ у апачей интерсное есть: Benchmarks tend to be a measure of configuration competance, rather than of server quality

 

Еще, вы намекаете, что IPC при асинхронной модели не требует синхронизации. Очереди там всякие и т.п. Атомарность записи чтения обьектов IPC в томже линуксе обеспечивается ядром, с точки зрения юзерспейса ее м.б. не видно, но это не значит, что ее нет

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Т.е. для имитации синхронности по идее нужно было обрабатывать события на сокетах при помощи select, а не каждое соединение в своем отдельном

потоке.

Это уже не синхронность, тк нет ожидания, нет последовательного выполнения кода. Синхронность подразумевает блокировку в ожидании чегото-там(таймера, чтения с диска итд).

 

Если в коде, скажем есть асинхронный таймер и синхронное чтение файла - это уже не синхронный код, но и не асинхронный - это гибрид, приводящий к проблемам.

 

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

 

Еще, вы намекаете, что IPC при асинхронной модели не требует синхронизации. Очереди там всякие и т.п. Атомарность записи чтения обьектов IPC в томже линуксе обеспечивается ядром, с точки зрения юзерспейса ее м.б. не видно, но это не значит, что ее нет

Но и не значит, что она есть.

На каждой ОС и железе по своему. У меня, например, она есть, но частично. В большинстве случаев ее нет, lock-free обеспечивается процессором и грамотным построением алгоритма очереди, но это все зависит от конкретного камня. Но даже если есть синхронизация, то блокируются приоритеты (пара инструкций), а не тяжеленные мютексы или полная блокировка прерываний. При чем эти блокировки очень короткие, только для работы со служебными полями очереди(парочка машинных слов). Сами данные в очередь пишутся(и читаются) при полностью разблокированной системе.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

т.е. если процесс блокируется вплоть до события на каком-то одном или нескольких дескрипторах сокетов, а потом последовательно обрабатывает эти события, то такой процесс по вашему уже работает не синхронно?

 

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

 

В том же JS тоже есть несколько реализаций потоков Web Workers API, например. Они используются для создания фоновых процессов в браузере. Дело в том, что долго работающие тяжелые скрипты могут блокировать страницу браузера (выглядит как зависание страницы). Особенно это заметно при работе с DOM браузера напрямую. Отсюда всякие проекты по отрисовке типа ReactJs. Так что не все так радужно.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

т.е. если процесс блокируется вплоть до события на каком-то одном или нескольких дескрипторах сокетов, а потом последовательно обрабатывает эти события, то такой процесс по вашему уже работает не синхронно?

Хм, что будет в самом обработчике события? Например, мне нужно каждому подключившемуся клиенту слать раз в секунду 100 рандомных байт? Ну или каждому отдать файлик гигов на 5? :)

 

Так что не все так радужно.

Не не все так радужно в браузерном(да и в Node)-JS. Но это не значит, что асинхронный стиль плохой. В SST, например есть приоритеты событий - вытеснение одних событий другими(по сути обычные прерывания) и там никаких тормозов нет.

 

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

Да это ясно, только синхронный стиль нам навязывает потоки, когда надо делать многозадачность. А асинхронный - нет, там многозадачность получается сама собой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...