LINUX.ORG.RU

Обновился инструмент для работы с агентами в C++: SObjectizer 5.5.5

 , , ,


1

2

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

Проект живет на SourceForge, распространяется под трехпунктной BSD-лицензией.

Версию 5.5.5 можно взять либо из секции Files на SF, либо из Svn-репозитория, либо из зеркала на GitHub.

Если говорить кратко, то в версии 5.5.5 появилось следующее:

  • вспомогательные шаблонные методы introduce_coop и introduce_child_coop, упрощающие создание и регистрацию коопераций;
  • возможность использования туплов в качестве типов сообщений;
  • фильтры для сообщений, которые позволяют анализировать содержимое сообщений и отбрасывать те из них, которые не интересны агенту получателю;
  • несколько новых примеров.

Так же подготовлены две новые части серии презентаций “Dive into SObjectizer-5.5”, более подробно рассказывающие о состояниях агентов и кооперациях агентов (все имеющиеся презентации собраны здесь).

Если интересны подробности, то сюда.

Отдельная благодарность Алексею Сырникову, как за помощь в подготовке этого релиза, так и за поддержку зеркала SObjectizer на GitHub-е.

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

Речь идет о создании на С++ всего что умеет Erlang.

Нет, не идет. Прочтите пост внимательнее. Прочтите пост, на который отвечали в этом посте.

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

Что такое «более производительную система», ***?

Ведите себя прилично. Что такое более производительная система - будет зависеть от задачи. Система, способная обрабатывать большее число запросов, например.

Или ты кроме локалхоста ничего не видел?

А при чем тут локалхост? Система может состоять из большого числа узлов. Смысл фразы это не изменит.

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

Речь шла об Эрланге, значит речь идет о распределенной отказоустойчивой системе. И тут появляется анон на белом коне и говорит о том что на С++ производительнее - все пишем на нем. Но что поделаешь - мозгов у анона мало.

Мы читали разные темы?

Вот на это высказывание отвечал тот анон:

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

Прочтите внимательнее. Речь о том, что если акторы, то обязательно эрланг. Нельзя C++.

Ответ:

Почему? Что за кидания в крайности?

Довольно справедливое замечание, не находите?

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

Ага, я увидел что речь _только_ об акторах. Смутило предложение:

Почему нельзя взять C++, использовать там акторы и получить более производительную систему, в том случае, если фичи плюсов тебе вцелом в данной системе важны?

Получить более производительную систему акторов? Что это значит тогда: быстрее создавать акторы или ускорить работу самих акторов?

Допустим, и то, и другое. Допустим что за одно и тоже время ваша система на С++ создает в два раза больше акторов чем на Erlang'e - 2000000 против 1000000.Сама по себе эта производительность имеет смысл только для синтетического теста. Куда важнее насколько эффективно системный шедулер может их распланировать. И вот тут-то у системы на С++ начнутся проблемы. Блокирующий вызов в акторе? Тормозится шедулер, остальные акторы стоят. Неотловленное исключение\сегфолт в акторе? Система останавливается. Доступ к общему ресурсу? Синхронизация, опасность блокировки шедулера. Вытесняющая многозадачность? Нет, только кооператив. В общем, в сухом остатке остается только производительность отдельного актора. Я и предложил нивелировать разрыв между C++, в данном случае, и чистым Erlang'ом с помощью NIF'ок, драйверов и пр. Ибо это элементарно проще, а по производительности будет идти ноздря в ноздрю с С++.

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

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

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

Ну так выучи человеческий. Твой кококошный язык тоже непонятен окружающим.

Ибо это элементарно проще, а по производительности будет идти ноздря в ноздрю с С++.

Пруфлинк на сравнения или обычное трепло.

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

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

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

Доступ к общему ресурсу? Синхронизация, опасность блокировки шедулера.

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

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

На да, если актор в C++ будет решать свою задачу за 100ms, а такой же в Erlang-е за 500ms, то в сухом остатке окажется пятикратный выигрыш в производительности.

Я и предложил нивелировать разрыв между C++, в данном случае, и чистым Erlang'ом с помощью NIF'ок, драйверов и пр. Ибо это элементарно проще, а по производительности будет идти ноздря в ноздрю с С++.

Т.е. Erlang превратится в клей, который будет склеивать между собой большие куски нативного кода. А что у нас там в нутрях С будет? Не это ли:

"...насколько эффективно системный шедулер может их распланировать...Блокирующий вызов в акторе? Тормозится шедулер, остальные акторы стоят. Неотловленное исключение\сегфолт в акторе? Система останавливается. Доступ к общему ресурсу? Синхронизация, опасность блокировки шедулера. Вытесняющая многозадачность? Нет, только кооператив."

Т.е. вы предлагаете прийти к тем же граблям, только завернутым в обертку Erlang-а?

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

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

Я и назвал этот шедулер системным. Это не шедулер ос.

Т.е. Erlang превратится в клей, который будет склеивать между собой большие куски нативного кода. А что у нас там в нутрях С будет?

Ну да, вот только благодаря этому клею писать на С++ меньше, грабель меньше - особенно если свести все к числодробильне. А все инфраструктурная и не требующая высокой производительности часть остается за Эрлангом.

cyanide_regime ()
Ответ на: комментарий от anonymous
static ERL_NIF_TERM open_card(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
    UNUSED(argc);
    clock_t start_clk = clock();

    if (!asound_res)
        asound_res = enif_open_resource_type(env, NULL, "asound_res", asound_handle_dtor, ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);

    char card_name[255] = {0};
    int mode = -1;

    if (enif_get_string(env, argv[0], card_name, 255, ERL_NIF_LATIN1) < 0)
        return enif_make_badarg(env);

    if (!enif_get_int(env, argv[1], &mode) || mode > SND_PCM_STREAM_LAST || mode < 0)
        return enif_make_badarg(env);

    asound_handle *h = (asound_handle*)enif_alloc_resource(asound_res, sizeof(asound_handle));
    bzero(h, sizeof(asound_handle));

    if (snd_pcm_open(&h->handle, card_name, mode, 0) < 0) {
        enif_release_resource(h);

        return enif_make_badarg(env);
    }
    snd_pcm_hw_params_malloc(&h->params);
    snd_pcm_hw_params_any(h->handle, h->params);
    snd_pcm_hw_params_set_access(h->handle, h->params, SND_PCM_ACCESS_RW_INTERLEAVED);

    unsigned val = 120000;
    int dir = 0;

    if (snd_pcm_hw_params_set_period_time_near(h->handle, h->params, &val, &dir) < 0)
        return enif_make_badarg(env);

    ERL_NIF_TERM res = enif_make_resource(env, (void*)h);

    enif_self(env, &h->owner);
    h->env  = enif_alloc_env();
    h->port = enif_make_copy(h->env, res);
    h->mode = mode;
    h->recording = 0;

    enif_release_resource(h);

    printf("Processor time used by program: %lg sec.\n", \
    (clock() - start_clk) / (double) CLOCKS_PER_SEC);

    return enif_make_tuple2(env, enif_make_atom(env, "ok"), res);
}

Processor time used by program: 0.005154 sec.

2> timer:tc(fun () -> easound:open(1) end).

{6869,{ok,<<>>}}

1.7 мс проигрыша в сравнении с чистым С.

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

Получить более производительную систему акторов?

Нет. Систему, которая реализует задачу. И использует акторы =) Я понял так.

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

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

Что это значит тогда: быстрее создавать акторы или ускорить работу самих акторов?

Думаю, что все же имелось в виду работа всей системы. Система же делает что-то полезное, а не только акторы создает, правда?

И вот тут-то у системы на С++ начнутся проблемы.

Язык тут ни при чем. Все будет зависеть от программистов.

Блокирующий вызов в акторе?

А зачем мы делаем блокирующий вызов в такой системе?

Неотловленное исключение\сегфолт в акторе?

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

Доступ к общему ресурсу?

Ну так думать-то нужно головой, правда?

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

Я и предложил нивелировать разрыв между C++, в данном случае, и чистым Erlang'ом с помощью NIF'ок

Это же менее удобно, чем C++. Если такого кода будет очень много, если он будет составлять существенную часть проекта, то возможно это обернется еще большим геморроем. Кстати, а что будет, если мы сделаем в таком коде сегфолт?

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

А зачем мы делаем блокирующий вызов в такой системе?

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

Ну так думать-то нужно головой, правда?

Опять же, он может быть в либе.

Это же менее удобно, чем C++. Если такого кода будет очень много, если он будет составлять существенную часть проекта, то возможно это обернется еще большим геморроем. Кстати, а что будет, если мы сделаем в таком коде сегфолт?

Это менее удобно, да. Но: 1) Ты получаешь всю инфраструктуру Erlang/OTP со всеми ништяками: супервизорами, акторами и распределенкой - экономишь время на разработку аналогичного решения на С\С++\etc 2) Сводишь к минимально необходимому уровню низкоуровневую возню

Минуса два: 1) Приходится писать обертки - nif, драйвера 2) Сегфолт в нативном коде - падает узел, тут никуда не деться

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

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

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

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

Это менее удобно, да. Но: 1) Ты получаешь всю инфраструктуру Erlang/OTP со всеми ништяками: супервизорами, акторами и распределенкой - экономишь время на разработку аналогичного решения на С\С++\etc 2) Сводишь к минимально необходимому уровню низкоуровневую возню

Минуса два: 1) Приходится писать обертки - nif, драйвера 2) Сегфолт в нативном коде - падает узел, тут никуда не деться

Значит в разных задачах можно делать по-разному. Значит не стоит говорить, что на C++ акторы бессмысленны...

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

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

Кстати, две мс это не так уж и мало.

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

Кстати, две мс это не так уж и мало.

Там интерпретируется функция. Если ее скомпилить, то у меня разница в 50-100 мкс получается.

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

Вот это вы предлагаете делать в больших проектах? Вы серьезно?

И нет ли у вас тут в коде ошибки? Вот здесь:

// Resource allocated.
    asound_handle *h = (asound_handle*)enif_alloc_resource(asound_res, sizeof(asound_handle));
    bzero(h, sizeof(asound_handle));

    if (snd_pcm_open(&h->handle, card_name, mode, 0) < 0) {
// Resource is freed on error.
        enif_release_resource(h);

        return enif_make_badarg(env);
    }
    snd_pcm_hw_params_malloc(&h->params);
    snd_pcm_hw_params_any(h->handle, h->params);
    snd_pcm_hw_params_set_access(h->handle, h->params, SND_PCM_ACCESS_RW_INTERLEAVED);

    unsigned val = 120000;
    int dir = 0;

    if (snd_pcm_hw_params_set_period_time_near(h->handle, h->params, &val, &dir) < 0)
// Is resource leaked on error?
        return enif_make_badarg(env);

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

snd_pcm_hw_params_set_period_time_near скопипастил из соседней NIF'ки чтобы немного «замедлить» функцию.

cyanide_regime ()
Ответ на: комментарий от eao197
/** ALSA params allocating */
static ERL_NIF_TERM open_card(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
    UNUSED(argc);

    if (!asound_res)
        asound_res = enif_open_resource_type(env, NULL, "asound_res", asound_handle_dtor, ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);

    char card_name[255] = {0};
    int mode = -1;

    if (enif_get_string(env, argv[0], card_name, 255, ERL_NIF_LATIN1) < 0)
        return enif_make_badarg(env);

    if (!enif_get_int(env, argv[1], &mode) || mode > SND_PCM_STREAM_LAST || mode < 0)
        return enif_make_badarg(env);

    asound_handle *h = (asound_handle*)enif_alloc_resource(asound_res, sizeof(asound_handle));
    bzero(h, sizeof(asound_handle));

    if (snd_pcm_open(&h->handle, card_name, mode, 0) < 0) {
        enif_release_resource(h);

        return enif_make_badarg(env);
    }
    snd_pcm_hw_params_malloc(&h->params);
    snd_pcm_hw_params_any(h->handle, h->params);
    snd_pcm_hw_params_set_access(h->handle, h->params, SND_PCM_ACCESS_RW_INTERLEAVED);

    ERL_NIF_TERM res = enif_make_resource(env, (void*)h);

    enif_self(env, &h->owner);
    h->env  = enif_alloc_env();
    h->port = enif_make_copy(h->env, res);
    h->mode = mode;
    h->recording = 0;

    enif_release_resource(h);

    return enif_make_tuple2(env, enif_make_atom(env, "ok"), res);
}

....


/** ALSA set period time */
static ERL_NIF_TERM set_period_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
    UNUSED(argc);

    asound_handle *h = NULL;
    unsigned val = 0;
    int dir = 0;

    if (!enif_get_resource(env, argv[0], asound_res, (void**)&h))
        return enif_make_badarg(env);
    else if (!enif_get_int(env, argv[1], (int*)&val))
        return enif_make_badarg(env);

    snd_pcm_hw_params_set_period_time_near(h->handle, h->params, &val, &dir);

    return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_int(env, val));
}

/** ALSA get period time */
static ERL_NIF_TERM get_period_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
    UNUSED(argc);

    asound_handle *h = NULL;
    unsigned val = -1;

    if (!enif_get_resource(env, argv[0], asound_res, (void**)&h))
        return enif_make_badarg(env);

    int dir = 0;
    snd_pcm_hw_params_get_period_time(h->params, &val, &dir);

    return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_int(env, val));
}

Вот так.

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

Это, конечно, уже лучше, но ошибок в вашем C-шном коде все равно предостаточно. Например, вы не контролируете коды возвратов функций snd_pcm... И если для какой-нибудь snd_pcm_hw_params_set_period_time_near это может и не страшно, то вот для snd_pcm_hw_params_malloc это сделать не мешало бы.

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

Но я слишком давно знаком с C++ и C, чтобы знать, что просто не будет. Для того, чтобы хорошо и надежно писать на C, нужно иметь очень большой опыт за плечами, да и довольно специфический взгляд на мир. Рассчитывать на то, что Erlang-еры смогут делать это на должном уровне не приходится. И ваш код тому подтверждение.

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

Это, конечно, уже лучше, но ошибок в вашем C-шном коде все равно предостаточно. Например, вы не контролируете коды возвратов функций snd_pcm... И если для какой-нибудь snd_pcm_hw_params_set_period_time_near это может и не страшно, то вот для snd_pcm_hw_params_malloc это сделать не мешало бы.

Для snd_pcm_hw_params_set_* эти проверки не важны в принципе - возвращаемое из NIF'а значение явно скажет удалось или не удалось. snd_pcm_hw_params_malloc - дергает обычный malloc, который NULL не вернет на нашей системе никогда.

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

Это напоминает оправдания из категории «я не пишу говнокод потому, что я просто не могу написать говнокод». Не серьезно, право слово.

Для snd_pcm_hw_params_set_* эти проверки не важны в принципе - возвращаемое из NIF'а значение явно скажет удалось или не удалось.

Ну смотрим внутрь вашей же set_period_time:

static ERL_NIF_TERM set_period_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
    UNUSED(argc);

    asound_handle *h = NULL;
    unsigned val = 0;
    int dir = 0;

    if (!enif_get_resource(env, argv[0], asound_res, (void**)&h))
        return enif_make_badarg(env);
    else if (!enif_get_int(env, argv[1], (int*)&val))
        return enif_make_badarg(env);

    snd_pcm_hw_params_set_period_time_near(h->handle, h->params, &val, &dir);

    return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_int(env, val));
}
Допустим, что snd_pcm_hw_params_set_period_time_near вернул отрицательное значение. Т.е. не выполнил своей работы. Как вы об этом сообщите наверх, ведь у вас параметры для make_tuple2 вообще не зависят от результата set_period_time_near.

snd_pcm_hw_params_malloc - дергает обычный malloc, который NULL не вернет на нашей системе никогда.

А гарантия этого «мамой клянусь!», не так ли? Где этот контракт в коде зафиксирован? Если в какой-то следующей версии вы задействуете вариант malloc-а, таки возвращающего NULL, вспомните ли вы о том, что где-то в ваших NIF-ах вызывается snd_pcm_hw_params_malloc без контроля кода возврата?

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

Допустим, что snd_pcm_hw_params_set_period_time_near вернул отрицательное значение. Т.е. не выполнил своей работы. Как вы об этом сообщите наверх, ведь у вас параметры для make_tuple2 вообще не зависят от результата set_period_time_near.

{ok, 120000} = easound:set_period_time(Handle, 120000).

int snd_pcm_hw_params_set_period_time_near (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, unsigned int * val, int * dir )

Returns:
0 otherwise a negative error code if configuration space is empty

Т.е. если он вернет < 0 значит все накрылось медным тазом еще до этого метода.

А гарантия этого «мамой клянусь!», не так ли? Где этот контракт в коде зафиксирован? Если в какой-то следующей версии вы задействуете вариант malloc-а, таки возвращающего NULL, вспомните ли вы о том, что где-то в ваших NIF-ах вызывается snd_pcm_hw_params_malloc без контроля кода возврата?

int snd_pcm_hw_params_malloc ( snd_pcm_hw_params_t ** ptr )
allocate an invalid snd_pcm_hw_params_t using standard malloc

malloc на нашей системе NULL не вернет никогда.

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

Видишь ли, смысла проверять все это особо нет - snd_pcm_hw_params_set_*_near может сказать что все ок, а нужное значение параметра не выставить. Т.е. я прошу размер, допустим, периода в 120 мс, snd_pcm_hw_params_set_period_time_near вернет 0, а размер периода выставит в 200 мс. И смысл всех это защитной лабуды? Мне проще косяк в поведении программы поймать паттерн-матчингом там где это нужно, а не городить километры защитного кода там где это особо не нужно.

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

Т.е. если он вернет < 0 значит все накрылось медным тазом еще до этого метода.

Поэтому нужно продолжать работать как ни в чем не бывало. Замечательно.

malloc на нашей системе NULL не вернет никогда.

А где же «мамой клянусь!»? Без этой мантры не канает.

Вы либо научитесь на C программировать, либо перестаньте народ смешить.

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

Поэтому нужно продолжать работать как ни в чем не бывало. Замечательно.

А то что в упаравляющей логике в Erlang'e такие проверки могут быть видимо для вас непостежимо?

А где же «мамой клянусь!»? Без этой мантры не канает.

На ЛОРе уже был пост по поводу того когда malloc вернет 0. Ищите и просветляйтесь. Смейтесь или не смейтесь, но на нашей системе проверять возвращенное malloc'ом значение бесполезно - оно всегда отлично от 0.

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

А то что в упаравляющей логике в Erlang'e такие проверки могут быть видимо для вас непостежимо?

Постижимо. Просто на мой деревенский взгляд, в Erlang-овском коде проверки будут проще, если возвращаемые значения будут иметь вид {ok,val} и {err}.

Смейтесь или не смейтесь, но на нашей системе проверять возвращенное malloc'ом значение бесполезно - оно всегда отлично от 0.

Ведь snd_pcm_hw_params_malloc возвращает не void*, а int. Это значение нужно проверять. А уже как у себя внутри snd_pcm_hw_params_malloc проверяет успешность malloc-а — это уже другой вопрос. Может это через errno делается или еще как-то иначе.

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

Речь шла об Эрланге, значит речь идет о распределенной отказоустойчивой системе

и NIF, который присовывая erlang превращается в тыковку, падает nif - падает вся erlang vm, вот это поворот! У erlang все такое, сам он алмаз вокруг чота говно

hizel ★★★★★ ()
Ответ на: комментарий от eao197
int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr)
{
      assert(ptr);
      *ptr = calloc(1, sizeof(snd_pcm_hw_params_t));
      if (!*ptr)
            return -ENOMEM;
      return 0;
}

Еще есть вопросы?

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

Ниф писать необязательно. Можно порт. Или целую ноду. Просто универсального рецепта нет, каждый случай надо отдельно рассматривать. Но выше заметили абсолютно верно. 500 vs 10000, почувствуйте разницу.

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

И вот ко всему, что он написал ты придрался к тому, что нет проверки после маллока на ноль? Царя на тебя нет. И да, неужели у тебя в со5 есть строка с catch bad_alloc?

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

Еще есть вопросы?

Да. Чем вы гарантируете, что у вас calloc _никогда_ не вернет NULL?

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

Вот только отладить 500 строк на С намного проще чем 10000.

Но сложнее, чем 250 на C++.

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

И вот ко всему, что он написал ты придрался к тому, что нет проверки после маллока на ноль?

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

Зато потом, почему-то, программирование на С++ — боль.

И да, неужели у тебя в со5 есть строка с catch bad_alloc?

Если бы вы чуть-чуть знали C++, то понимали бы, что после того, как исключения в C++ получили широкое распространение, надобности в перехвате bad_alloc не стало. А вот необходимость контроля возврата malloc/calloc, а потом ручного вызова free, как была, так и осталась.

Но, как было показано выше, эксперты по Erlang-у, считающие себя знатоками C, про это либо не знают, либо не в состоянии использовать на практике.

Из чего легко делается вывод о качестве C-шного кода, который будет написан апологетами подхода «Сначала все на Erlang-е, а потом узкие места на C».

Ну и чтобы не быть голословным. Вот код на C++ и so5 (вот описание самой задачи).

В C++ном коде нет ни одного new/delete, хотя динамическая память там используется повсюду. Там нет ни try/catch, ни проверок кодов ошибок. Тем не менее, в случае возникновения оных все нормально подчищается.

Если кто-то думает, что написав на Erlang-е и переписав часть решения на C для увеличения производительности, получится сильно короче, проще в сопровождении и быстрее, пусть покажет это на практике :)

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

Ну ты опять обобщил, как и с недовольными эрлангом блогерами. Типа если один не может, то и все не могут. С логикой у тебя проблемы.

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

Кстати, интересно получается с проблемой блокирующего вызова в акторе. Я бы даже сказал, что это настолько большой изьян что и без catch bad alloc весело.

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

malloc() проверяй, эксепшены не лови! Логика типичного программиста на С++.

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

Тоесть ты не понимаешь разницу между кодом возврата, который нужно провепять на месте и эксепшином, который может быть прокинут на самый верхний уровень? Типичный я_знаю_как_лучше балабол. И да, кукарекалки кудахтающие о ненуле ммалока, никогда не писали для серверов, на которых ресурсы искусственно ограничивают для юзера/группы/сессии/соединения/чтототутеще. И еще кукарекалки не в курсе, что помимо линуксовых серверов есть не линуксовые (и это даже не оффтопик), на которых малок вполне вепнет 0.

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

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

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

А то баги и дыры в C-шных программах находят направо и налево. Каждый второй, если не первый, на форумах кричит, что программирование на C — это боль. Но когда нужно NIF-ку для Erlang-а написать, то, внезапно, все мастера. Там, наверное, C какой-то другой.

Только вот один товарищ, который ратовал за Erlang+C показал свой C-шный код и оказалось, что там есть что подправить.

Кстати, интересно получается с проблемой блокирующего вызова в акторе. Я бы даже сказал, что это настолько большой изьян что и без catch bad alloc весело.

Ну давайте посмотрим на источники блокировки агента:

1. Длительное использование CPU-интенсивной операции. Грубо говоря, перемножение матриц или подбор ключа. Насколько хорош будет диспетчер Erlang-а, если такими задачами начнут эрланговые акторы заниматься? И насколько эти акторы будут тормозить по сравнению с C++ными?

2. Обращение к внешней библиотеке. Например, работа с Oracle через OCCI или MSSQL через ODBC. Когда эрланговый актор дернет соответствующую NIF-ку, а оттуда вызов уйдет в OCCI/ODBC, неужели эрланговый диспетчер будет как-то управлять заблокированным потоком?

3. Синхронный I/O. Ту да, стандартная библиотека С++ не содержит пока готовых асинхронных API для ввода-вывода. Тут Erlang будет круче. До тех пор, пока в плюсах не задействуют ASIO/libevent/libuv/ACE и т.д.

Так что все не так плохо, как вы это пытаетесь выдать.

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

Linux memory overcommiting. malloc() всегда вернет значение отличное от 0.

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

Другие Unix-ы? Не Unix-ы? Не, не слышал.

malloc() проверяй, эксепшены не лови! Логика типичного программиста на С++.

Exception safety? Не, не слышал.

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

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

void KokokoClass:alloc_koko() {
    ... something throws std::bad_alloc
}

void KokokoClass:koko() throw (MyKokoException) {
    Koko::Ptr ptr = alloc_koko();
    
}

...

void main() {
   try {
      KokoClass().koko();
   } catch (const std::bad_alloc &) {
   }
   ...
}

Прокидывай чаще, кукурекалка.

И да, кукарекалки кудахтающие о ненуле ммалока, никогда не писали для серверов, на которых ресурсы искусственно ограничивают для юзера/группы/сессии/соединения/чтототутеще. И еще кукарекалки не в курсе, что помимо линуксовых серверов есть не линуксовые (и это даже не оффтопик), на которых малок вполне вепнет 0.

Я уже несколько раз написал, тупой ты идиот, что на нашей системе нету ничего что поменяет это поведение malloc'a. Или ты не только тупой но еще и слепой? И о каких платформах говорит кукарекалка если там код, использующий ALSA? Ты просто туп, сгинь отсюда.

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

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

man Advanced Linux Sound Architecture.

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

man Advanced Linux Sound Architecture.

Правильно ли я понимаю, что раз вы намеренно ограничиваете разговор ALSA, то применимость ваших рекомендаций по поводу «Erlang+C будет проще и быстрее, чем C++» следует ограничивать той единственной системой, которой cyanide_regime пишет для одного единственного дистрибутива Linux-а?

eao197 ★★★★ ()
Ответ на: комментарий от cyanide_regime
void KokokoClass:koko() throw (MyKokoException) {

Вы когда в последний раз C++ в руки брали?

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

Разве это не валидный C++ код? Про то что с С++11 это deprecated я знаю. Но тем не менее, такие конструкции компилятся и юзаются.

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

Ну и вообще, что за экивоки. Вот пример кода когда эксепшен на верхнем уровне не поймать. Либа чужая и сорцев у вас нет.

cyanide_regime ()

Произошло то чего стоило и ожидать: камень в сторону С++ - как сразу «так уже не пишут!!!11», объясняешь что malloc смысла проверять нету, т.к. код просто рухнет в следующей функции (ибо он никогда 0 не вернет, а при записи туда сгенерируется исключение) - «Erlang + C - говно, пишем на С++».

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

Речь идет о модуле для ALSA, чем мне еще ограничивать этот разговор?

Речь идет о том, что Erlang+C — это реальная альтернатива C++.

В качестве подкрепления этого тезиса вы приводите C-шный код. В котором вам указывают на ваши ошибки.

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

Ну OK, за свою жизнь я столько наслушался этих самых «в моем конкретном случае», что уже не воспринимаю их всерьез. Посему вы просто в очередной раз продемонстрировали, что как только речь идет о C-шном коде, так все оказывается работоспособным в очень узком диапазоне ограничений.

Вот точно так же и ваш совет «Erlang+C» можно всерьез воспринимать только если очень и очень сильно ограничить контекст.

Разве это не валидный C++ код?

В нем есть синтаксические ошибки. Причем, судя по тому, что ошибка в декларации метода класса у вас повторяется несколько раз, вы C++ не видели очень давно.

Про то что с С++11 это deprecated я знаю.

Обсуждаемый здесь SO5 требует C++11, под C++03 он не собирается.

Ну и вообще, что за экивоки. Вот пример кода когда эксепшен на верхнем уровне не поймать. Либа чужая и сорцев у вас нет.

Это просто вы не понимаете, как писать на C++ не заморачиваясь на типы выбрасываемых исключений. Ключевые слова вам обозначили — exception safety. Если ваш код обеспечивает exception safety хотя бы на уровне basic guarantee, то вам без разницы, бросается ли bad_alloc, bad_cast, bad_exception, invalid_argument или еще что-то. Поэтому вы имеете возможность просто писать new или make_unique, или make_shared и не заморачиваться на проверки кодов возврата (*).

А вот в C не так, результат malloc-а нужно контролировать, если речь идет о хоть сколько-нибудь кроссплатформенном коде. И если вы приводите пример кода в котором таких проверок нет, то не удивляйтесь, что ваш код хорошим не называют.

* если только речь не идет о специфических условиях, в которых C++ные исключения запрещены ключиками компилятора, например, жесткий real-time.

eao197 ★★★★ ()
Последнее исправление: eao197 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.