All streams
Search
Write a publication
Pull to refresh
14
0
Alex Nekipelov @nekipelov

программист

Send message
Кто сказал, что там чистые сокеты? Где в boost реализация HTTP и FastCGI? Где в POCO и Mongoose поддержка FastCGI?
Своя библиотечка, также сделанная для разработки web приложений на C++.
И добавлю то же C++ приложение, но в режиме fastcgi через nginx:

Concurrency Level:      100
Time taken for tests:   1.208 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      1560000 bytes
HTML transferred:       210000 bytes
Requests per second:    8275.49 [#/sec] (mean)
Time per request:       12.084 [ms] (mean)
Time per request:       0.121 [ms] (mean, across all concurrent requests)
Transfer rate:          1260.72 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.9      0       7
Processing:     3   12   2.5     12      32
Waiting:        2   12   2.7     12      32
Total:          3   12   2.2     12      32

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     12
  75%     12
  80%     13
  90%     13
  95%     16
  98%     19
  99%     21
 100%     32 (longest request)


Но как правильно указал автор, не совсем корректно сравнивать ничего не делающее приложение.
В подобном тесте fastcgi дает большие накладные расходы. Ведь NodeJS не был спрятан за http сервером? Если сравнивать C++ приложение, работающее в качестве http сервера, результаты будут значительно лучше. Сравнил с моей поделкой.

NodeJS:

Concurrency Level:      100
Time taken for tests:   1.877 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      1150000 bytes
HTML transferred:       140000 bytes
Requests per second:    5328.73 [#/sec] (mean)
Time per request:       18.766 [ms] (mean)
Time per request:       0.188 [ms] (mean, across all concurrent requests)
Transfer rate:          598.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       6
Processing:     1   19   3.4     17      33
Waiting:        1   19   3.4     17      32
Total:          4   19   3.4     17      33

Percentage of the requests served within a certain time (ms)
  50%     17
  66%     18
  75%     18
  80%     19
  90%     25
  95%     26
  98%     30
  99%     31
 100%     33 (longest request)


C++ приложение:

Concurrency Level:      100
Time taken for tests:   0.493 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      1370000 bytes
HTML transferred:       210000 bytes
Requests per second:    20287.80 [#/sec] (mean)
Time per request:       4.929 [ms] (mean)
Time per request:       0.049 [ms] (mean, across all concurrent requests)
Transfer rate:          2714.29 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   0.6      2       7
Processing:     1    3   0.8      3       8
Waiting:        1    2   0.7      2       7
Total:          3    5   0.8      5      11

Percentage of the requests served within a certain time (ms)
  50%      5
  66%      5
  75%      5
  80%      5
  90%      6
  95%      6
  98%      9
  99%      9
 100%     11 (longest request)


Хотя мой код далеко не оптимальный, если сравнивать с nginx.
По-моему этот код как раз у автора написан правильно.


Вы правы, что-то я уже забываю C++03 и полагаюсь на C++11 :-)
А мой взгляд вот за это зацепился:

while (it != m_mapClients.end()) //Перечисляем всех клиентов
{
    if (!it->second->Continue()) //Делаем что-нибудь с клиентом
        m_mapClients.erase(it++); //Если клиент вернул false, то удаляем клиента
    else
        it++;
}


Должно быть вот так:

it = m_mapClients.erase(it);


С другой — мне не нравится когда старожилы хабра уводят в минуса людей с желанием писать программы и статьи. Пусть даже уровень этих статей далеко не дотягивает до уровня желаемого.


Я не минусовал но подозреваю, что причина минусов в том, что автор категорически не хочет прислушиваться к мнению более опытных разработчиков (особенно это заметно по комментариям к первой статье). А с таким подходом далеко не продвинуться.
Думаете, после заявления: «пишу и буду писать код в заголовочных файлах если мне это удобно», стоит читать код? :-)
Тогда уж в Windows следует использовать IOCP (Input/output completion port).
Для сборки программ — конечно следует выбрать что-то вроде cmake/qmake/scons и т.д. Однако make создан не только для компиляции, это просто удобная программа, умеющая отслеживать зависимости. Например вы хотите сайт на markdown писать, make в помощь:

SRCS = index.md page1.md page2.md
HTMLS = $(SRCS:.md=.html)

.PHONY: all clean install uninstall

all: $(HTMLS)

%.html: %.md
        markdown < $^ > $@


Ну и любые подобные задачи. Так что make не перестает быть удобным и полезным инструментом. Хотя да, использую я его все реже и реже… :-)
Советую поглядеть вывод make -p, там очень много полезного. Переменная CC по умолчанию содержит имя C компилятора (т.е. на Linux это gcc, также есть и CXX и другие). CFLAGS по умолчанию пустой, но используется вот так:

$ CFLAGS=-g make
$ CFLAGS=-O2 make


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

Шаблон .c.o указывает, каким образом из .c файлов получить .o файлы.

%< и $@ — это переменные, значение которых содержит имя цели или зависимости.

PS: где-то у меня был более универсальный Makefile с генерацией зависимостей и поиском исходников. Если найду, могу показать.
Я бы все же добавил, что сила make в универсальности. И последний пример у меня выглядел бы примерно так:

TARGET = hello
PREFIX = /usr/local/bin
SRCS = main.c hello.c
OBJS = $(SRCS:.c=.o)

.PHONY: all clean install uninstall

all: $(TARGET)
$(TARGET): $(OBJS)
            $(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
 
.c.o:
            $(CC) $(CFLAGS)  -c $< -o $@

clean:
            rm -rf $(TARGET) $(OBJS)
install:
            install $(TARGET) $(PREFIX)
uninstall:
            rm -rf $(PREFIX)/$(TARGET)
Я бы посоветовал вам смотреть на что-нибудь вроде www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/examples.html#boost_asio.examples.ssl.

Это и кроссплатформенно, и на C++, и не подвержено проблеме c10k и вообще самый правильный способ.
Ваши выводы не совсем верны. Для вашего php приложения не имеет значения, кто выступает http сервером. Однако в других случаях эта разница может присутствовать. Например при использовании long-polling или когда приложение получает POST запросы (apache вроде бы еще не научился держать тысячи соединений, которые постят по 1Кб в минуту) и т.д.
Наверное у хороших программистов не бывает жен, детей и ипотеки…
Вызов Sleep(0), даже при замене на SwitchToThread — плохое решение. Переход на уровень ядра и переключение контекста обходятся очень дорого. А тут оно может выполнится много раз. Почему бы не воспользоваться событиями для WinAPI и condition variables для POSIX?
IMHO, не очень хорошая идея. Придет человек вроде меня и спросит: а такое «Вконтакте»? Вот я понятия не имею, что там за приложение, зачем оно нужно и что от него требуется. Конечно же если вы собираетесь делать подобное приложение, то вам и не подойдет такой программист. Поэтому если и использовать подобный подход, то не «берем популярное, большое (в плане функционала) и сложное (в плане реализации) приложение», а берем именно то приложение, функциональность которого схожа с будущими задачами для этого программиста.
Вообще то WinAPI, как и огромное количество другого системного кода, это C, а не C++, а стало быть наличие там данных макросов — нормальная ситуация.


Вот в том то и дело, что там код на C, поэтому макросы, хоть и вызывают неудобства, но без них не обойтись. А мы говорим о C++, и о коде, который макросов не требует вообще.

Пусть код со скобками для меня привычнее, но это нисколько не мешает воспринять условия в исходном примере кода с однострочными ифами — так очень многие пишут.


Я конечно опять нарываюсь на минусы, но все же нормальный код не должен так выглядеть. В книгах так часто пишут чтобы сократить объем. Но там и примечания ставят соответствующие. Но в статье на сайте нет смысла экономить строки.

С void on_clients() скорее согласен, отступ там желателен, но почему бы не сообщить о таком допущении в личку?


Следуя логике большинства — код компилируется? Да, значит он правильный. Так зачем что-то сообщать? Мои претензии к коду — исключительно мое личное дело, я никому не навязываю свой стиль. Тем более, что стилей очень много. Мне вот венгерская нотация не нравится, но не сообщать же теперь об этом в личку каждому автору, посмевшему ее использовать? :-)

Ситуация с
typedef std::vector<client_ptr> array;

это ещё один привет из C++03.


Я специально показал следующий пример с array из boost. Asio появился в boost начиная с версии 1.35, открываю первый попавшийся пример и вижу вот такие строки:

#include <boost/array.hpp>
...
boost::array<char, 1024> data_;


Пруф: www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/example/allocation/server.cpp

Сомнительно, что автор пишет о boost asio и не знает о контейнере array. А если знает, то зачем вводить потенциально конфликтный тип данных?

Пожалуй соглашусь только с привидением типов в стиле C при использовании в C++, а вот всё остальное: макросы, goto, и сырые указатели использовать можно если это действительно необходимо.


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

p.s: руководствуясь написанным у Вас в пункте 3 вообще не понимаю зачем было писать что либо в данном топике, если данная тема Вам не интересна.


Тема как раз интересна, иначе бы я не стал открывать этот топик и тем более пролистывать до комментариев.

Ну и предлагаю завершить эту дискуссию :-)
1. Плох сам факт использования макросов. Это как если бы вместо for/while использовать метку и goto, вроде такого:

    int i = 0;
label:
    // code
    if (++i < 100)
        goto label;


Казалось бы, ну что тут плохого? Код на C++, компилируется и работает без ошибок. Значит код правильный и использовать можно. Примерно такими же соображениями руководствовался программист, сделавший в где-то в WinAPI макрос с именем max и мне уже много лет приходится писать #ifdef max\n#undef max\n#endif. Чем именно плохи макросы, по моему, написано в любой книге по программированию на C++ и также дана рекомендация не использовать их. Но давайте я не буду учить вас программированию.

2. Тема для холивара — это какой стиль лучше. Тут же, откровенно говоря, стиля нет вообще. Код написан небрежно.

Вот например:

void on_read(const error_code & err, size_t bytes) 
{
    if ( err) stop();
    if ( !started() ) return;
    std::string msg(read_buffer_, bytes);
    if ( msg.find("login ") == 0) on_login(msg);
    else if ( msg.find("ping") == 0) on_ping();
    else if ( msg.find("ask_clients") == 0) on_clients();
}


и тут уже ниже

void on_clients() 
{
    std::string msg;
    for(array::const_iterator b =clients.begin(),e =clients.end(); b != e; ++b)
    msg += (*b)->username() + " ";
    do_write("clients " + msg + "\n");
}


Глядя на первый кусок уже и не кажется, что строка msg += (*b)->username() + " "; является телом цикла. Ведь даже отступа нет.

void read_answer()
{
    already_read_ = 0;
    read(sock_, buffer(buff_),
    boost::bind(&talk_to_svr::read_complete, this, _1, _2));
    process_msg();
}


Тут вообще аргумент функции на новой строке.

typedef std::vector<client_ptr> array;
array clients;


Вот зачем специально запутывать людей, создавая тип array, который на самом деле vector? Это ведь разные типы данных, один динамический массив, другой использует память на стеке. Кстати говоря, члены класса talk_to_client:

    char read_buffer_[max_msg];
    char write_buffer_[max_msg];


должны быть объявлены вот так:

    boost::array<char, max_msg> read_buffer_;
    boost::array<char, max_msg> write_buffer_;


Ну и все остальное в том же духе. Конечно кому-то кажется, что человек может писать так, как ему хочется. Использовать макросы и goto, привидение типов в стиле C, free и delete вместо RAII… Надо проработать программистом не один год и в разных командах, чтобы осознать важность этих правил.

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

  1. Макросы MEM_FN. Перевод для начинающих, ну и не надо начинающих программистов приучать к макросам. Это же C++.
  2. Форматирование исходных текстов ужасно. Я понимаю, что это нудно и неудобно… но код должен быть оформлен красиво.
  3. Ну и содержимое на столько простое и очевидное, что лично я не вижу смысла в этом переводе. Документация у boost не на столько хороша, как у Qt, но все же имеется.


Разумеется минус я тоже не стал ставить.
Поэтому я и написал: «Почитал комментарии и очень удивлен». Я не удивлен статьей, там все как и должно быть. А удивлен тем, что судя по комментариям, и на IT ресурсе люди точно также используют честный ответ на подобный вопрос. И даже советуют не использовать вопросы, ответы на которые можно нагуглить…

Information

Rating
Does not participate
Location
Москва и Московская обл., Россия
Registered
Activity