LINUX.ORG.RU

Кто там кукарекал про С++?


1

8

Задача: разработать кроссплатформенное клиент-серверное приложение под Windows/Linux на С++ (boost, ace, etc.), клиент построчно считывает с консольки введёные числа, отправляет на сервер, сервер в ответ плюёт разложением чисел на простые множители. Стандартное тестовое задание, ничего интересного.

Ну что же, собрался духом, за вечер родил чуть около пол тысячи строк, чтоб всё как положено: асинхронность, многопоточность, все дела. Такое ощущение, коллеги, будто накормили грязью, кресты не умеют ни в замыкания, ни в нормальную асинхронность, ни в управление памятью, они вообще ничего не умеют. Вроде бы, написано 5 строк, а на деле почти не фига не делают, код раздут, абсолютно невыразителен, я уж не представляю что с ним будет, если его ещё раскидать на десяток классов, как это обожают делать отдельные особо одарённые личности.

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

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : io_service_(io_service),
      acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
  {
    session* new_session = new session(io_service_);
    acceptor_.async_accept(new_session->socket(),
        boost::bind(&server::handle_accept, this, new_session,
          boost::asio::placeholders::error));
  }
  .......

Смеха ради, да и чтоб не вырвало от такого кода, накидал за полчаса решение на Haskell.
Что получилось:

  • Разбор параметров командной строки
  • Клиент-серверная архитектура
  • Полностью асинхронный многопоточный tcp-сервер
  • Поддержка unicode, IPv6 и BigInteger из коробки
  • Мемоизация (благодаря ленивости) из коробки
  • Полная кроссплатформенность (*nix, Mac OS, Windows etc.)
  • Правильность тривиально доказывается мат. индукцией по коду
  • Исходник чуть больше 60 строк (в 8 раз меньше, чем на крестах)

Если поднатужиться (я не стал) и заменить алгоритм нахождения простых чисел/простых множителей на более оптимальный, то ко всему прочему получаем автоматическую распараллелизацию алгоритмов из коробки (см. Data Parallel Haskell) и произодительность на уровне чистого Си/Фортрана.

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

★★★★★

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

Кстати, хаскель код в треде и около, по ссылкам, такой же как и этот пример.

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

А как нужно?

Смотря кому - школьникам и этот вариант прокатит, а в продакшене последние 15 лет все ловят эвенты.

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

форк
последние 15 лет все ловят эвенты

Одно другому какбе и не мешает.

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

[nginx] в accept уперся

Имеется в виду, что accept в master и не масштабируется, но он ведь в worker.

пруф?

Unlike traditional servers, Nginx doesn't rely on threads to handle requests

Общее место.

кстати, в traditional servers accept тоже в одном треде

Имеется в виду, что даже если не брать nginx, а какой нибудь traditional servers с моделью тред-на-соединение, accept всё равно будет в одном треде.

Да ладно

да

Это учебный и на 30 лет устаревший пример

А как нужно?

Смотря кому - школьникам и этот вариант прокатит, а в продакшене последние 15 лет все ловят эвенты.

  1. traditional servers (= с моделью тред-на-соединение) делали и делают именно так, то есть с accept-ом в loop-е до fork-а очередного треда.
  2. event-based серверы делают accept внутри своего event loop-а, количество этих loop-ов может быть > 1 (разнесено по тредам / процессам / ядрам) и у них может быть какой-то master.
  3. В языках с лёгкой конкурентностью сервера пишутся как (1), но под капотом у них (в I/O manager VM) работает (2).

Вот erlang (yaws) это продакшн или нет? А, между прочим, никакой ловли эвентов (только в кишках VM). Это же касается snap который обсуждался.

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

traditional servers (= с моделью тред-на-соединение)

У тебя какое-то не правильное понимание «traditional servers». Я про апач, IIS и т.п. Там нет модели «тред на коннект». Там типовая модель «пул потоков» (или костыль для php - «пул дочерних процессов») обслуживающий «пул соединений». (1а)

event-based серверы делают accept внутри своего event loop-а

Нет. Типовые event-based серверы в одном потоке только ловят события. Обработку событий, в т.ч. акцепт, делают _как правило_ в других потоках. Более того, в нормальных API для event I/O типа IOCP main loop'а даже не видно.

Вот erlang (yaws)

Я не про эрланг. Я только про

в traditional servers accept тоже в одном треде.

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

Там типовая модель «пул потоков» (или костыль для php - «пул дочерних процессов») обслуживающий «пул соединений».

Это уже дальнейшее усложнее. По сути просто однотипное масштабирование этой простейшей модели.

Мне интересно, что значило замечание ckotinko «nginx упёрся в accept».

Обработку событий, в т.ч. акцепт, делают _как правило_ в других потоках.

nginx/src/event/ngx_event_accept.c это не accept в event loop?

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

Это уже дальнейшее усложнее.

Это другая модель: 1:1 vs M:N.

По сути просто однотипное масштабирование этой простейшей модели.

Это не принято называть «масштабированием». «Масштабирование» - это возможность копирования модели.

nginx/src/event/ngx_event_accept.c это не accept в event loop?

Нет, конечно же. Это коллбэк на появление нового соединения. Вот main loop:

ngx_event.c

void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
...
    if (ngx_posted_events) {
        if (ngx_threaded) {
            ngx_wakeup_worker_thread(cycle);

        } else {
            ngx_event_process_posted(cycle, &ngx_posted_events);
        }
    }
}

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

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

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

Т.е. он делает accept в master, а дальнейшую обработку передаёт какому-либо worker-у? Может ли быть тогда смысл иметь несколько master-ов?

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

Т.е. он делает accept в master,

Он не делает accept в master. Как и во всём AIO он подписывается на уведомление о событиях. Событием может быть запрос на создание/закрытие сокета или на чтение/запись данных.

Все события обрабатываются одним и более воркерами. В т.ч. и accept.

Может ли быть тогда смысл иметь несколько master-ов?

«Мастер» нужен в первую очередь для управления - SIG{TERM, USR, KILL}, и т.п. Попутно он делает де- и просто инициализацию, а также выполняет роль «свадебного генерала» в той самой main loop - реагирует на события и обновляет на них подписку, если необходимо. Этот пункт узким местом может быть только при очень кривой реализации.

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

Да не за что.

Все события обрабатываются одним и более воркерами. В т.ч. и accept.

Имеется в виду, что сам вызов accept делает воркер.

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

Ну это не tradidional server, это tradidional example )

sv75 ★★★★★ ()

Смеха ради, да и чтоб не вырвало от такого кода, накидал за полчаса решение на Haskell.

Стандартное тестовое задание, ничего интересного

Так хаскель же и предназначен для стандартных тестовых заданий. Попробовал бы написать что-то серьезное — навернул бы говна по полной.

anonymous ()

>петушиный

ЛОРу как-то не очень идет это слово.

uRandom ()

а плохому танцору гоги мешают.

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