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

TC хаскель с C++ сравнивал. Как если бы хаскель мог занять нишу C++ (или наоборот).

ТС жжет напалмом. Но я проявлю чудеса сдержанности, не найду ему либу на С++ с которой эта задача решается так же просто как и на хаскеле/питоне/и т.д. и не ткну этой либо в евойное лицо! Потому что мне она нафик ненужна, дурную работу я забесплатно делать не люблю, а денег от него вряд ли дождешься... ;-)

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

но многопоточность будет...

python может в многопоточность? tornado / twisted, вроде, event-loop делают в таких случаях.

http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks — warp при этом не делает event-loop, а просто forkIO на каждый запрос (т.е. полагается исключительно на лёгкую конкурентность GHC).

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

python может в многопоточность?

Может. Там честные потоки + GIL, но GIL операциям I/O не мешает, все равно все висит в ожидании данных.

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

Там честные потоки + GIL

Честные потоки = OS threads это, конечно, хорошая многопоточнотсь, но плохая конкурентность. Делать веб-приложение с моделью поток/процесс на соединение можно только в языках с лёгкими процессами (которыми управляет VM) вроде Erlang или Haskell, в остальных языках приходится делать event-loop завязанный на механизм event notification предоставляемый OS (как в tornado или в node).

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

кстати спрошу шарящего русскоязычного, может ли быть ситуация с потоками haskell, когда стандартный event loop с epoll висящем на всех сокетах будет выгоднее forkIO?

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

Ну вам, усачам,в любви и карты в руки(с)

Тут я уже совсем дилетант, пасую.

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

а, что на хабре GIL страшно ругают [1]?

А за что его хвалить? Для меня например критично то, что если в треде С-шную функцию запускаешь то все остальные висят пока она не отдасться;-( Т.е. всю эффективную многопоточность приходится лабать на С/С++. А так ничего, I/O хорошо вроде параллелится, и с блокировкой разделяемых объектов проблем нет (она просто не нужна как правило, если это не файлы). А остальное пофик, если на питоне пытаешься написать что то аццки быстрое с загрузкой всех ядер, то это диагноз... ЯП как бы не для того.

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

может ли быть ситуация с потоками haskell, когда стандартный event loop с epoll висящем на всех сокетах будет выгоднее forkIO?

Рантайм языка с lightweight concurrency представляет I/O просто как особый лёгкий процесс, при этом выполнение I/O в таком процессе является event-driven (с использованием select/epoll/etc.).

http://www.haskell.org/ghc/docs/7.0.1/html/users_guide/release-7-0-1.html

On POSIX platforms, there is a new I/O manager based on epoll/kqueue/poll, which allows multithreaded I/O code to scale to a much larger number (100k+) of threads.

Т.е. машинерия с event loop уже скрыта в рантайме языка. I/O manager сам проводит буферизацию и будит/останавливает процессы выполняющие IO при поступлении/недоступности данных (т.е. когда в его event loop происходят события). Примерно то же самое происходит и при обращении с STM.

Ну и по ссылке выше на бенчмарк warp выглядит лучше чем snap.

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

Ну и по ссылке выше на бенчмарк warp выглядит лучше чем snap.

Ещё:

The Monad.Reader Issue 19

At this point, the performance of Mighttpd 2 (without logging) became 21,601 queries per second. We also measured the performance of nginx, which is written in C. The performance of nginx (without logging) is 22,713 queries per second. Finally, we could say that a web server written in Haskell was comparable to one written in C.

Since Mighttpd 2 does not share essential information among user threads, we don’t have to share any information among pre-forked processes. We compared Mighttpd 2 and nginx with three worker processes. The performance of Mighttpd 2 (without logging) is 61,309 queries per second, while that of nginx (without log- ging) is 30,471. Note that we are no experts in the use of nginx, so we might have been able to obtain better results by tweaking its configuration. We can at least say that the pre-fork technique is very effective for these kinds of servers.

The performance of nginx (3 workers with logging) is 25,035 queries per second, while that of Mighttpd 2 (3 workers with logging) is 31,101 queries per second. Though Mighttpd 2 is still faster, nginx loses only 18% of its performance through logging whereas Mighttpd 2 loses 49%. This indicates that more efficient logging systems might be possible. However, we have currently run out of ideas for further optimizations. Implementing a better logging system remains an open problem. Feedback would be appreciated.

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

PiPi> вынеси в метод и не будет

Методы на каждый чих? Решение, достойное наркомана!
Кстати, за это я ту же жабу и не люблю - она не оставляет выбора парадигмы.

PiPi> Сдается у кого-то просто руки из жопы...

При таком подходе руки из жопы у всех.

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

Методы на каждый чих? Решение, достойное наркомана!

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

При таком подходе руки из жопы у всех.

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

PiPi ()
Ответ на: комментарий от AIv

если в треде С-шную функцию запускаешь то все остальные висят пока она не отдасться;-(

Си-функция может сама отдать GIL.

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

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

anonymous ()
Ответ на: комментарий от AIv

ХЗ, я сам не делал - только читал в блоге PyPy, что это возможно. Python/C API Reference Manual, section 8.1 намекает на:

Py_BEGIN_ALLOW_THREADS
...Do some blocking I/O operation...
Py_END_ALLOW_THREADS
tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner
#ifndef TEST_HPP
#define TEST_HPP
#include <math.h>
#include <Python.h>

double f(){
	Py_BEGIN_ALLOW_THREADS
	double x= 3.;
	for( int i=0; i<1e8 ;i++ ) x = exp(log(x));
	return x;
	Py_END_ALLOW_THREADS
}

#endif
#!/usr/bin/python
from test_thr import *
import thread, time

L = []

def g() :
    t0 = time.time()
    L.append( f() )
    print L, time.time()-t0

#print f()

t0 = time.time()
thread.start_new_thread( g, () ) 
print 'I', time.time()-t0
t0 = time.time()


thread.start_new_thread( g, () )
print 'II', time.time()-t0

while len(L)<2 : time.sleep(1.)
$ time ./run_test_thr.py 
I 0.000167846679688
II 6.60419464111e-05
Ошибка сегментирования

real    0m28.462s
user    0m56.592s
sys     0m0.056s

От сегфолта не удается избавится...

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

return x;
Py_END_ALLOW_THREADS

Ы. Python/C API Reference Manual, section 8.1 как бы намекает нам:

«The Py_BEGIN_ALLOW_THREADS macro opens a new block and declares a hidden local variable; the Py_END_ALLOW_THREADS macro closes the block».

Лично мне return из блока кажется плохой идеей.

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

O! Точно, я туплю... так работает: [code=C] double f(){ double x= 3.; Py_BEGIN_ALLOW_THREADS for( int i=0; i<1e8 ;i++ ) x = exp(log(x)); Py_END_ALLOW_THREADS return x; } [/code] Спасибо! Отечественная наука вас не забудет;-)

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

O! Точно, я туплю... так работает:

 
double f(){
	double x= 3.;
	Py_BEGIN_ALLOW_THREADS
	for( int i=0; i<1e8 ;i++ ) x = exp(log(x));
	Py_END_ALLOW_THREADS
	return x;
}
Спасибо! Отечественная наука вас не забудет;-)

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

Ну смотри что таке эксепшн? Это информация об ошибке содержащая в себе информацию о вызовах приведших к ошибке. Что мешает сериализоват её? Да возможно перехватыват ты потом будешь не RuntimeError, а SerializedRuntimeError и все. PDF не читал. техника слабовата

demmsnt ()
Ответ на: комментарий от geekless

Из всего этого только Ruby позволяет выражаться по существу, без 100500 бесполезных символов.

Попробовал написать задание в ОП на ruby: http://pastebin.com/CkUK96RQ

Получилось кратко и вроде читабельно (хотя, т.к. это, практически, мое первое знакомство с Ruby, там может быть г*внокод). Но один фатальный недостаток, из-за которого в реальности я бы обязательно предпочел что-угодно другое: если активно 1-2 потока (например, мы послали очень большое простое число), то на все запросы, посланные при этом, он отвечает с большой задержкой. Судя по всему, виноват кривой GIL, т.к. в IronRuby, например, такой проблемы нет (но он почему-то не хочет подхватывать trollop).

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

Да, в MRI единственный профит от потоков в том, что один поток может заниматься вычислениями, пока другие делают I/O. В твоей чисто вычислительной задаче на текущей реализации MRI получается херня вместо многопоточности. Это серьёзный минусище.

geekless ★★ ()

Кстати, смотрел тут видюшку с SPJ насчет параллелизма и хаскеля. В конце он описывает один из видов параллелизма данных — называет его Nested Parallelism — как две капли воды похожего на то, что делает Левченко сотоварищи за вычетом клеточных автоматов на сдвинутых сетках.

Дает отсылки на труды некого Guy Blelloch и 1990-й год. Утверждает, что еще никто этого не сделал. Обещает в «следующем релизе» DPH. Гордитесь, партизаны хреновы.

Там же вскользь упоминает eDSLный компилятор для CUDA. Это к вопросу о кодогенерации.

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

спроси его имя и добавь благодарность в исходники, а то забудет :)

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

Ну смотри что таке эксепшн? Это информация об ошибке содержащая в себе информацию о вызовах приведших к ошибке.

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

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

Вот например нагуглил, об этом? http://research.microsoft.com/en-us/um/people/simonpj/papers/ndp/fsttcs2008.pdf

Насколько я понял поглядев по диагонали, речь идет о хранении данных в деревьях. Так это пожалуйста, этой идее уже скока лет то... Рекурсивные контейнеры первым никак не Левченко придумал. Но вот ничего похожего на LRnLA я там не нашел.

Гордитесь, партизаны хреновы.

Без пруфа эта бездна экспрессии выглядит как вброс обиженного школьника из Ярославля. И где мои 5 тыс руб за оказание поисковых услуг по сочетанию «стена Фокса»?

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

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

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

Насколько я понял поглядев по диагонали, речь идет о хранении данных в деревьях.

там всё чуть хитрее, но действительно не относится к LRnLA.

И где мои 5 тыс руб за оказание поисковых услуг по сочетанию «стена Фокса»?

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

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

где решаются какие то другие, совершенно общие задачи

Я не спорю. Но, согласись, есть некоторые общие моменты:

1. Граф зависимостей
2. Редуцирование размерности. У SPJ исключительно 2D -> 1D. У вас же ND -> ND.
3. Переход от мелкозернистого параллелизма к средне/крупнозернистому. Для чего нужно учитывать локальность — в вашем случае, cost model — в случае SPJ.

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

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

А почему тогда люди не пользуются другими реализациями?

IronRuby и JRuby, например, умеют потоки и не имеют GIL (притом если первый - полуживой, то второй активно развивается вроде).

Deleted ()
Ответ на: комментарий от Macil

Но, согласись, есть некоторые общие моменты:

Согласен, есть. Но тот же граф зависимостей опять таки не Левченко придумал (и не хачкелисты) - Левченко придумал метод разбиения графа зависимостей для некоторого класса задач матфизики. Каковое разбиение кстати меняет сложность задачи с линейной до N^(1+1/D), за счет чего все и работает - обычные совр. компьютеры плохо приспособлены к решению задач линейной сложности.

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

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

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

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

А я и не шучу!

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

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

Если бы это было бы так. И хрен бы я бы за эту статью если бы не копал в сторону клеточных автоматов для кластерного анализа/датамайнинга, и моделирования систем (бизнес) правил с помощью КлА.

В частности, выводы статьи останутся верными также и для параллельного моделирования эволюции произвольных КлА с локальным шаблоном, а не только для порождаемых рассмотренным ЯЛСМ.

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

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

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

Если бы это было бы так.

Ну я у него спрошу за эту статью;-) От клеточных автоматов кстати уже давно ушли...

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

Взаимно;-)

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

Вот тут Кто там кукарекал про С++? (комментарий) у no-such-file был к тебе вопрос.

Ну и Macil спрашивал про то, как LRnLA соотносится вот с этим http://www.cs.cmu.edu/~scandal/nesl.html

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

AIv ★★★★★ ()
Ответ на: комментарий от no-such-file

Каша в голове.

10^9 узлов это примерно 6*2^60 байт.

тут ошибка примерно в 2^30 раз

Для теста достаточно и того, что возможности кэша перекрыты на порядок, дальше все тоже самое пока память совсем не кончится.

это не так. Во-первых, кэшей три уровня, а во вторых некоторые особенности процесса кэширование таблиц страниц виртуальной памяти дает еще несколько ступенек «второго порядка», скажем 64MB/512MB/4GB/...

давайте и ваши результаты для 6 эксабайт. Тогда поверю.

Пока задач такого размера мне не ставили. Если кто-то поставит --- сделаю, результаты выложу...

Там черным по белому написано, что классические методы оптимизации вполне эффективны при отсутсвии параллелизма

там этого не написано, и не может быть написано, потому как написать так без множества оговорок --- это написать ниочем.
Скажем, Вы Intel® 64 and IA-32 Architectures Optimization Reference Manual читали?
Так вот там весьма много разных «классических методов оптимизации» описано, и каждый применяется во вполне определенной ситуации, и тогда лишь эффективен, а в других случаях --- нет, нужны другие.

при «дешевом» параллелизме (т.е. на классических многопроцессорниках)

эээ, «дешевизна» эта (должен заметить, обычно под этим термином понимается «распараллеливание» изначально последовательных программ при помощи omp) весьма дорого обходится во всех остальных отношениях.

когда накладные расходы на синхронизацию ничтожны.

И это не так, совсем не так. И в теории, и по факту.

VLev ()
Ответ на: Каша в голове. от VLev

Re: Каша в голове.

:)

Тогда самый первый вопрос, собственно с чего все и началось... Почему именно С++? Почему не X Y Z.

Macil ★★★★★ ()
Ответ на: комментарий от no-such-file

если бы задачи не требовали применения ПВС, то все ок

У Вас проблемы с формальной логикой. Тут наоборот написано о том, что все настолько «не ок», что без ПВС никак не обойтись.

Кроме того, исходя из первичного тезиса, Вы путаете «классические методы дискретизации» и «классические методы оптимизации».
Кроме всего прочего --- это термины совершенно разных наук.

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

Та же проблема с логикой. В этом абзаце я пытаюсь объяснить медицинский факт, наблюдаемый сплошь и рядом --- отсутствие этого самого «окея» в параллельных приложениях, написанных весьма квалифицированными программистами.
Если Вам приятнее жить в светлом мире закона Амдала --- то я помешать тут не могу, но не надо привлекать мои тезисы для доказательств своих заблуждений.

Выходит так, что на обычной SMP архитектуре, или скажем на CUDA, где все считается за примерно равные промежутки и особой проблемы в синхронизации нет, классические методы не будут уступать. Или как?

Не так. У «обычной SMP архитектуры» масса других бутылочных горлышек. В subj-евой статье я об этом не писал, но за прошедшее время успел их изрядно изучить.
Что касается CUDA, то это разговор особый. Предметно, надеюсь смогу ответить где-то через год.

VLev ()
Ответ на: комментарий от anonymous

сударь, вы е$$$сь, ace — кривое поделие, которое не возможно нормально использовать в продакшене

anonymous ()
Ответ на: Re: Каша в голове. от Macil

Почему именно С++? Почему не X Y Z.

Для начала очень простой ответ: у c++ самый мощный оптимизирующий компилятор из известных мне.

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