Pull to refresh
154
0.1
Григорий@bfDeveloper

Программист на C++, D, Brainfuck

Send message
void mySum(int[] r, Task tid) {
    int result = r.sum;
    tid.send(result);
}

void example() {
    auto s = [7, 2, 8, -9, 4, 0];

    auto c = Task.getThis;
    runTask(toDelegate(&mySum), s[0..$/2], c);
    runTask(toDelegate(&mySum), s[$/2..$], c);
    int x = receiveOnly!int();
    int y = receiveOnly!int();

    logInfo("%d %d = %d", x, y, x+y);
}

Проект, который можно запустить, здесь.
Это почти полный эквивалент. По крайней мере делает ровно то же самое, и я постарался сделать код максимально похожим, чтобы прослеживались параллели.
Основное отличие — отсутствие канала. Вместо этого посылается сообщение. Полной аналогии типизированных каналов в vibe.d нет, есть две альтернативы:

  • Сообщения. Буферизированые в очереди, типизированные, но посылаются в сопрограмму, а не в отдельный объект. Минимальная шаблонная обёртка и это будет полная аналогия каналов
  • TaskPipe. Ведёт себя как канал, можно буфферизировать, можно не буфферизировать, но предназначен только для данных. То есть только ubyte[]

Цикл суммирования я тоже убрал, это слишком много бессмысленного кода. Благодаря нормальным шаблонам в D есть нормальные обобщённые алгоритмы. Их не надо писать каждый раз заново, при этом они не теряют в производительности. Это как раз та область, где D нет равных. Go тут тоже нет равных, но в обратном смысле — этой фичи нет вообще и без нормальных шаблонов быть не может.
И вот из того, что я видел

Мне кажется проблема в том, что асинхронность в D вы не видели.

Наконец-то можно создавать поток на каждое подключение и на каждую фоновую операцию и не бояться, что это сожрет всю память.

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

в D предлагают опять эти уродливые события и колбеки

Я вас не понимаю, честно. Найдите в vibe.d хоть один колбек. Кроме разве что onConnection и onTimer. Но они и инициируются не кодом, а некой третьей стороной, для них нет линейного кода. Так проиходит и в Go и в C#.
А для чтения, записи, подключения к кому-то нет никаких колбеков или событий. События есть для общения между сопрограммами, но это тот же самый select в Go, только гораздо универсальнее.
Бывают ситуации, где предлагается альтернатива: колбек или возвращаемое значение. Просто так получилось, что чистые колбеки работают чуть-чуть быстрее и это API оставлено. Но код всё равно можно писать синхронно.
Всё сделано так чтобы было удобно писать именно линейный код: предоставляются асинхронные линивые диапазоны для чтения/записи, автоматически закрываются соединения при выходе из скоупа и тд, и тп. Чего-чего, а callback hell, это точно не про vibe.d
Fiber в стандартной библиотеке. Vibe.d поддерживает множество ивентлупов (libevent, libev, win32, собственная библиотека libasync). Большинство библиотек для асинхронных операций основываются на vibe.d, он стал почти стандартом, поэтому проблемы совместимости нет. Кроме того модель сопрограм такова, что если функция не выполняет асинхронных действий сама, то ей не требуется какая-то особая поддержка асинхронности. То есть любые синхронные библиотеки отлично работают в асинхронном коде.
Хорошо у него с производительностью. Сравнивал простые HTTP сервер и клиент с Go, получилось примерно одинакого. Причём масштабируются и Go и D одинакого хорошо. С учётом обработки и всяких парсингов JSON D оказывается быстрее. Есть мнение, что самый быстрый JSON как раз написан на D. Бенчмарк конечно не совсем честный, но точно претендент на лидерство.
В бенчмарке по вашей ссылке vibe.d есть, правда работал в один поток (была взята старая версия фреймвёрка с досадным багом). PR с нормальной многопоточной версией был отправлен вовремя, но почему-то его не приняли. Ждём следующего запуска, чтобы увидеть правильные результаты.
"Сложный" пример предлагал чуть выше, а за совсем простыми можете обратиться сюда. Пример оттуда:

auto conn = connectTCP("time-c.nist.gov", 13);
logInfo("The time is: %s", conn.readAllUTF8());

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

while(true) {
        c.write(buf.data);
        c.write(['\0']);
        buf.clear();
        c.readUntil(buf, ['\0'], SIZE);
    }
}

Это кусок одного очень простого теста, слегка усложнённый вариант эхо сервера. Пишет в сокет то, что получил. Что c.write, что c.readUntil — асинхронные операции, в которых произойдёт переключение волокон исполнения. С моей точки зрения Fibers — абсолютный эквивалент goroutines и, что уже субъективно, гораздо удобнее async из C#.
Про асинхронность не правда. Корутины есть (называются Fiber), кроме того есть целый фреймвёрк для асинхронного io: vibe.d
Совсем правильный пример конкатенации должен быть таким:
auto s = concat(s1,s2,s3);
, где concat — ленивый диапазон отсюда (https://github.com/ericniebler/range-v3), ну или из std, когда будет.
В этом случае вообще не произойдёт выделения памяти. Понятно, что если дальше нужен быстрый произвольный доступ, то всё равно лучше создать именно строку через range::copy(concat(...), s). Но если потом вы будете читать пару символов или только последовательно, то лучше оставить ленивый диапазон.
Согласен, язык не так популярен на хабре, стоило подробнее описать, зачем вообще писать на D. Восполню пробел парой ссылок на статьи на хабре:
https://habrahabr.ru/post/246623/
https://habrahabr.ru/post/224419/
https://habrahabr.ru/post/197480/
https://habrahabr.ru/post/154345/
Есть динамический биндинг OpenCL. http://code.dlang.org/packages/derelict-cl
Это просто описанный интрефейс к обычному OpenCL. Как хэдеры в сях. Аналогичная штука есть для CUDA
http://code.dlang.org/packages/derelict-cuda
Холиварный вброс, но всё же отвечу. Затем, что быстрее. Бытрее писать и внезапно быстрее работает.
Писать быстрее благодаря обилию алгоритмов, шаблонов, нормальной типизации, безопасности (в виде RAII, контрактов, тестов и сборке мусора) и кучи плюшек (http://dlang.org/ctod.html).
Быстрее работает — немного спорное утверждение. Эквивалентный код чуть медленнее, но на D не пишут как на C. Банальный пример: там, где в C будет массив или копия массива, в D будет ленивый диапазон. По моему опыту замена конкатенации строк на ленивый диапазон даёт прирост скорости 6 раз. Опыт портирования проектов с С или С++ говорит об ускорении результата. Например, в фейсбуке портировали небольшую библиотеку https://code.facebook.com/posts/729709347050548/under-the-hood-building-and-open-sourcing-flint/ D версия работает быстрее.
Чтобы повторить то, что даёт стандартная библиотека диапазонов в D, понадобится куча кода на C, который никто просто не будет писать. Писать быстрый код на D быстрее. Писать обычный код ещё быстрее.
Писать супероптимизированный код на D тоже проще, так как ничто не мешает опуститься до уровня C, пользоваться указателями и всеми низкоуровневыми оптимизациями вплоть до встроенного ассемблера. Вот только мощность шаблонов и прочих фич времени выполнения будет помогать даже на низком уровне и всем этим можно пользоваться.
Ситуаций, в которых D уступает C или C++, очень мало и с каждым днём становится всё меньше.
Бенчмарков не ставил, но не вижу причин, почему он должен отличаться от x86. Бэкенд у компиляторов одинаковый, сами языки примерно на одном уровне производительности, так что +- то же самое.
Где-то вы тут запутались. В целом всё верно, М1 — начальная масса, М2 — конечная. Вот только откуда М1+М3+М4=const? Из соображений, что стартовая масса всегда одинаковая? Это не совсем правда, скорее М1+М3+М4<=const.
По самой формуле (М1+М3+М4)/(М2+М3) = C = e^(V/I) = const, так как e^(V/I) от массы не зависит. Так как М1/М2 = С, то (М3+М4)/М3 = С, отсюда увеличение массы топлива для посадки М3+М4 = С*М3. Это линейная зависимость. Для удельного импульса Мерлина в 2.73 км/с и скорости расстыковки в 3.4 км/с получаем С = e^1.24542 = 3,4744. То есть надо взять дополнительно в три с половиной раза больше топлива, чем нужно для посадки.
Причин много.
Парашют тоже что-то весит и выигрыш получается несущественным. На тех скоростях даже без парашюта аэродинамическое торможение существенно, а ради последних 100 м/с тащить парашют не очень выгодно.
Парашютом сложно управлять. Можно, но сложно. Точность посадки будет хромать.
Маску нужно отработать вертикальную посадку для будущих миссий на Марс.
Вообще-то линейная. image
В показателе экспоненты отношение скорости к удельному импульсу. Масса входит строго линейно. Да, коэффициент для современных ракет около 30, но экспоненты там нет. Чтобы вывести в 2 раза больший груз нужна ракета в 2 раза больше.
Почему-то последнее время эта ошибка очень часто появляется в обуждениях космосмической темы. Не в обиду будет сказано, но похоже большинство комментирующих формулу Циолковского в глаза не видели.
Не согласен с искажением термина coroutine. На компилируемом языке вполне возможны корутины. Тот же boost:coroutine или даже go. Абстракция та же самая: системных потоков мало, реальных потоков исполнения с независимыми стеками много. Это же не просто таски, обрабатываемые пулом потоков, это полноценные корутины, которые можно приостановить на середине, а потом продолжить с того же места. А поток может быть и один.
Однако предложение действительно сырое, не надо тащить чужеродные непродуманные концепции в язык. Похоже MS форсит свою реализацию, даже в свой компилятор поддержку добавили.
Очень рекомендую посмотреть диапазоны в D. В C++ слишком много синтаксического шума, за которым идею не так просто разглядеть. Кроме того для D гораздо больше документации, статей и примеров из реальной жизни. Для начала рекомендую http://www.tutorialspoint.com/d_programming/d_programming_ranges.htm
а так же примеры отсюда: http://dlang.org/phobos/std_range.html и отсюда: http://dlang.org/phobos/std_algorithm_iteration.html
Хорошая идея и реализация. Ещё бы это подружить со стремлением С++ к диапазонам https://ericniebler.github.io/std/wg21/D4128.html
То есть ваш список это же перемешанные в кучу данные и ленивые генераторы. Их можно более менее вписать в ленивые диапазоны, которые не владеют данными, если отделить хранение в обычный std::list/vector/set/… .
я понял что допустил ошибку и сравнение оказалось не совсем корректным. iota динамически создает данные которые принимает функция sliced. И соответственно мы не трогаем память до момента последней ее релокации.

Я не совсем понимаю, почему это ошибка. В реальном коде тоже будут места, которые так оптимизируются, диапазоны для того и нужны. Если задача была протестировать поиск среднего, то iota вообще не должно было быть в бенчмарке. А так это одно из основных преимуществ диапазонов. Ленивость это фича. Не нужно считать, хранить, выделять память под сущности, которые эффективно генерируются на лету. Не так давно на С++ сталкивался с ситуацией, когда ленивый диапазон выигрывал у конкатенации строк просто за счёт ухода от аллокации. А ведь на нём как и на строке работают все алгоритмы стандартной библиотеки.
Хороший пример для обработки изображений был http://habrahabr.ru/post/218429/ Это конечно не ndslice, но хорошо раскрывает потенциал диапазонов как таковых. Особенно восхищает ситуация, когда несколько поворотов изображения дают 360 градусов, компилятор это понимает и выкидывает код вообще. Это же не просто частный случай, это демонстрация просторов для оптимизмции.
Пожертвовавший свободой ради безопасности не заслуживает ни свободы, ни безопасности. (Бенджамин Франклин)

Information

Rating
3,744-th
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity