LINUX.ORG.RU

1.Когда нужно использовать один или другой?

Технически, они ничем не отличаются. С точки зрения структуры, service дополнительно маркает бин, что это не просто какой-то компонент, а часть сервисного слоя.

См. документацию

Indicates that an annotated class is a "Service", originally defined by Domain-Driven Design (Evans, 2003) as "an operation offered as an interface that stands alone in the model, with no encapsulated state."

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

Попроще, разницы нет, работают одинаково.

Возьми самый простой crud, у тебя будет три слоя в приложении - контроллер, в котором ты определяешь ресты, репозитории, которые умеют работать с БД и сервисы, которые знают как обработать запрос и в какой репозиторий сходить. Можно сервисы пометить @Component? Можно, работать будет так же. Но принято отмечать их как @Service, просто для удобства

hippi90 ★★★★★
()
  1. Технически разницы нет. Обычно все используют @Service.

  2. Неправда, гораздо быстрей.

vbr ★★★★★
()
Последнее исправление: vbr (всего исправлений: 1)
Ответ на: комментарий от Lusine
  1. Технически пофиг. А практически чтоб тебе было понятнее в своём коде у тебя есть выбор обзывать то что ты делаешь сервисом или компонентом.

  2. Нет, иногда, it depends. Тут смотри какая штука: идеально написанная программа на Java всегда будет медленнее идеально написанной программы на C++, которая в свою очередь проиграет сишке и растишке (но не так сильно, сишка при этом немного выиграет у растишки за счёт того что позволяет делать грязные и очень опасные вещи), а те проиграют идеальному ассемблерному коду (с оговоркой что пишет его первоклассный специалист). Но по факту, никто просто так не будет писать программу в 100 000 строк на C++, чтоб уделать программу в 1000 строк на Java. И не факт что даже если возьмутся, то из-за ошибок не сделают её хуже. Потому оптимизируют только то, что узко. В плане таких оптимизаций C++ выиграет у Java, но только если разработчик на C++ понимает что делает и не гнушается даже ассемблером. А уж про SIMD и говорить не приходится. Другое дело, что не в каждом алгоритме тебе помогут SIMD с ассемблером. Но там где помогут C++ порвёт Java как тузик грелку, пока у последней не доделают вальгалу (а зная как долго её делают, я поверю что ИИ будет всё писать к тому моменту, когда это случится вообще без участия человека). ИРЛ зная уровень «сеньоров» на отечественном рынке труда (почему он такой оставим на размышление тебе, когда будешь искать работу), то написать качественный и быстрый код (SIMD, ассемблерные вставки, серьёзная математическая оптимизация алгоритмов и их выбор под конкретную задачу, учитывая не только O(N), но и реальный объём данных на которых работает алгоритм конкретно в их программе, например, сортировка пузырьком будет быстрее ванильного квиксорта с куда лучшим O(N), если надо сортировать группы по 5 элементов), на C++ смогут полтора человека. Но бодаться с тяжёлой Java в прогретой виртуальной машине трудно - из-за того что она не просто компилируется, а переводится в байт код и исполняется в виртуальной машине, последняя на основе статистики может делать дополнительные оптимизации на лету, ускоряя хреново написанный код. И выходит что если код написан одинаково плохо на C++ и Java (а это именно так в больших программах, чем она больше, тем больше там говна), то Java запросто и победит его.

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от peregrine

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

1brc challenge смотрит на это с ухмылкой

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

Он с SIMD через Graal. Со всеми плюсами и минусами самого Graal (не всякий Java код будет работать в Graal, рефлексия и всё что с ней связано не смогут, если специальным, особо геморройным методом их не делать).

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

пока у последней не доделают вальгалу

Уже заморжили, в следующем JDK будет первая итерация. Думаю к LTS доведут до минимально полезного состояния.

maxcom ★★★★★
()
  1. Пофиг.
  2. И лет 20 назад на кывте, и с год назад на лоре видел оценки, что среднестатистическая реальная программа на C++ быстрее жавы раз в 30. Это совпадает с моими ощущениями и как юзера (e.g. отзывчивость QtCreator vs IDEA – и то, и другое не дураками написано), и как программиста (суммарно наверное лет по 10 что в том, что в другом; и моя оценка не про безумно-заумный стек jee/spring). А любителей длинно рассуждать о нюансах и кейсах я скромненько спрошу, на чём написаны AAA-игры.
dimgel ★★★★★
()
Ответ на: комментарий от peregrine

идеально написанной программы на C++, которая в свою очередь проиграет сишке и растишке

Довольно спорный момент в сравнении C++ vs Rust. Откуда у последнего будет преимущество в производительности? Там

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

От качества абстракций реального кода. У C++ ехал шаблон через шаблон и очень высокоуровневые абстракции за которые приходится платить. Да, на C++ можно писать быстрый код, если писать его как на Си с классами.

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

У C++ ехал шаблон через шаблон и очень высокоуровневые абстракции за которые приходится платить

Каким образом за шаблон приходится «платить» чем-то кроме времени компиляции?

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

За сам шаблон нет, а за то как их лепят там где не нужно, не понимая работы ПК на физическом уровне очень даже придётся (у иных программистов на C++ понимание такое: есть процессор, он считает быстро-быстро, но потоков мало, есть GPU оно считает медленно, но потоков жопой жуй, есть жесткий диск, он медленный, есть оперативка она быстрая, а про кеш процессора, выравнивание, шины к GPU и много чего ещё они не знают, про ветвление и предсказание ветвления что-то слышали краем уха, но что, как оно работает, не, ерунда какая-то, надо код бахать). Проблема не в шаблонах, а в некоторых (многих) разработчиках на C++, которые для решения элементарных вещей начинают лепить дикую дичь на высоких абстракциях (да, пыхтящий компилятор это разруливает, когда может, но он не всемогущ). Тот же code bloat это плохо для такого языка как C++, сишник попадёт в кеш процессора и всё у него будет хорошо и быстро, а на плюсах прям на шаблонах можно так раздуть код, что он из кеша вывалится и будет медленно.

Пнул тут ИИ-шницу (не писать же пример руками, а готового говнокода на C++ давно не видел и стараюсь на него не смотреть), как-то так, например, можно обосраться с шаблонами:

#include <iostream>
#include <vector>
#include <chrono>

// Макрос для искусственного раздувания тела функции,
// чтобы она гарантированно забивала кэш инструкций (I-Cache) при дублировании.
#define REPEAT_10(X) X X X X X X X X X X
#define HEAVY_LOGIC(target) REPEAT_10(target = (target * 33 + 11) % 1024;)

// Функция, чтобы компилятор не оптимизировал и не удалял "ненужный" код
void doNotOptimize(void* p) {
    volatile auto t = p;
    (void)t;
}

// ============================================================================
// 1. ВАРИАНТ С ШАБЛОНАМИ (Раздувает код)
// ============================================================================
template <size_t W, size_t H>
struct TemplateBuffer {
    std::vector<int> pixels;
    TemplateBuffer() : pixels(W * H, 5) {}

    // __attribute__((noinline)) запрещает встраивание, чтобы код оставался в функциях
    // и забивал кэш инструкций при генерации множества копий.
    __attribute__((noinline)) void applyFilter() {
        for (auto& p : pixels) {
            HEAVY_LOGIC(p);
        }
        doNotOptimize(pixels.data());
    }
};

// Исправленный макрос: теперь суффикс корректно склеивается с числами
#define CONCAT_INNER(a, b, c) a ## b ## _ ## c
#define CONCAT(a, b, c) CONCAT_INNER(a, b, c)

#define RUN_TEMPLATE_BENCH(W, H) \
    TemplateBuffer<W, H> CONCAT(buf_, W, H); \
    CONCAT(buf_, W, H).applyFilter();

void runTemplateBloatTest() {
    RUN_TEMPLATE_BENCH(100, 100); RUN_TEMPLATE_BENCH(101, 100);
    RUN_TEMPLATE_BENCH(102, 100); RUN_TEMPLATE_BENCH(103, 100);
    RUN_TEMPLATE_BENCH(104, 100); RUN_TEMPLATE_BENCH(105, 100);
    RUN_TEMPLATE_BENCH(106, 100); RUN_TEMPLATE_BENCH(107, 100);
    RUN_TEMPLATE_BENCH(108, 100); RUN_TEMPLATE_BENCH(109, 100);
}

// ============================================================================
// 2. ВАРИАНТ БЕЗ ШАБЛОНОВ (Компактный код)
// ============================================================================
struct RuntimeBuffer {
    std::vector<int> pixels;
    RuntimeBuffer(size_t w, size_t h) : pixels(w * h, 5) {}

    // Код скомпилирован ровно один раз. Функция «сидит» в кэше процессора.
    __attribute__((noinline)) void applyFilter() {
        for (auto& p : pixels) {
            HEAVY_LOGIC(p);
        }
        doNotOptimize(pixels.data());
    }
};

void runRuntimeCompactTest(RuntimeBuffer& b0, RuntimeBuffer& b1, RuntimeBuffer& b2, 
                           RuntimeBuffer& b3, RuntimeBuffer& b4, RuntimeBuffer& b5, 
                           RuntimeBuffer& b6, RuntimeBuffer& b7, RuntimeBuffer& b8, 
                           RuntimeBuffer& b9) {
    b0.applyFilter(); b1.applyFilter();
    b2.applyFilter(); b3.applyFilter();
    b4.applyFilter(); b5.applyFilter();
    b6.applyFilter(); b7.applyFilter();
    b8.applyFilter(); b9.applyFilter();
}

// ============================================================================
// ГЛАВНЫЙ ЦИКЛ ТЕСТИРОВАНИЯ
// ============================================================================
int main() {
    const int ITERATIONS = 30000; // Количество повторений для точности

    std::cout << "Running benchmarks (" << ITERATIONS << " iterations)..." << std::endl;

    // --- Тест 1: Шаблоны ---
    auto start1 = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < ITERATIONS; ++i) {
        runTemplateBloatTest();
    }
    auto end1 = std::chrono::high_resolution_clock::now();
    auto duration1 = std::chrono::duration_cast<std::chrono::microseconds>(end1 - start1).count();

    // --- Тест 2: Без шаблонов ---
    RuntimeBuffer b0(100, 100); RuntimeBuffer b1(101, 100);
    RuntimeBuffer b2(102, 100); RuntimeBuffer b3(103, 100);
    RuntimeBuffer b4(104, 100); RuntimeBuffer b5(105, 100);
    RuntimeBuffer b6(106, 100); RuntimeBuffer b7(107, 100);
    RuntimeBuffer b8(108, 100); RuntimeBuffer b9(109, 100);

    auto start2 = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < ITERATIONS; ++i) {
        runRuntimeCompactTest(b0, b1, b2, b3, b4, b5, b6, b7, b8, b9);
    }
    auto end2 = std::chrono::high_resolution_clock::now();
    auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>(end2 - start2).count();

    // Вывод результатов
    std::cout << "\nResults:" << std::endl;
    std::cout << "1. Template (Code Bloat):   " << duration1 << " us" << std::endl;
    std::cout << "2. Runtime (Compact Code):  " << duration2 << " us" << std::endl;
    
    double speedup = (double(duration1) - duration2) / duration1 * 100;
    std::cout << "\nRuntime variant is " << speedup << "% faster!" << std::endl;

    return 0;
}

Собирать и запускать так:

g++ -O3 benchmark.cpp -o bench_test
./bench_test

Да, ИИ-шка тут немного сжулила, но для примера этого нормально.

PS

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

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
  • Markdown
Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария