LINUX.ORG.RU

Garnet - кэш от Microsoft, написан на C#, делает и Redis, и Dragonfly

 , , garnet, ,


0

5

Как видно из бенчмарков, это сейчас вообще самый быстрый сервер структур данных на всём диком западе:

https://microsoft.github.io/garnet/docs/benchmarking/results-resp-bench

Парктически полностью совместим с Redis на уровне API, но при этом:

  • Имеет либеральную MIT лицензию, как и все последние крупные проекты MS, и этим крайне выгодно отличается от Redis
  • Написан на C#, и позволяет удобно расширять сервер
  • Делает по производительности и Redis, написанный на Си, и Dragonfly написанный на C++

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

Я кстати, в свое время написал на C# видеостриминг-сервер, и клиент, практически не используя кресты(было немного C++/CLI для связи с COM итд), и проблем с производительностью там не было. Но что я - вон целый MS Research делает продукты вон какого уровня.

★★

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

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

гугл такого не знает

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

А почему ты так зациклился на производительности выхлопа шарпа? 1-2% кода ведь можно переписать и на Сях/Rust, etc. аналогично Garnet?

C# - это ведь в первую очередь про продуктивность разработчика, а не только производительность скомпилированного бинарника?

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

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

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

А кто-то считал, сколько всего в мире понаписано плюсового говнокода? Ведь настоящий плюсовый профи стоит огого сколько денег, и то может облажаться время от времени, ведь он человек, а не детерминированный робот-транспайлер типа Haxe->C++.

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

потому что отдельные фрагменты .NET оптимизированы вплоть до ручного кода на асме.

А фрагменты С++ нет? У него и оптимизатор встотыщраз лучше. Я заметил, по постам в интернете, что обычно наоборот, люди которые не имеют большого опыта, удивляются насколько быстро работают их программы, когда они переписывают их на C/C++. И только имея опыт и там и там, можно нормально писать на C#, Java.

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

О, нашел. Суть такова.

Real-World приложения это естественно, не хелловорлды из синтетических тестов, со вставками на асме, это раз. А два - они вовсю засраны умными указателями. В следующем тесте я пытаюсь эмулировать реальное приложение на C++(смотрите сорцы вебкита, ггг), C# и лиспе соответственно, с кучей типа «умных» объектов, с коллекциями этих объектов, а не просто матрицами на стеке, итд, в наиболее нативном виде для языка как он используется в больших системах, а не на хелловорлдах. Песни про оптимизации и закатывание солнца вручную, поэтому, засуньте себе в жопу, тест не про это.

Лисповый код собирать так: sbcl --no-userinit --no-sysinit --load test-sbcl.lisp

(declaim (optimize (speed 3) (safety 0)))

(defun copy-vector (vector)
  (declare (type simple-vector vector))
  (let* ((length (length vector))
         (new-vector (make-array length)))
    (dotimes (i length)
      (setf (svref new-vector i) (svref vector i)))
    new-vector))

(defun test (n length)
  (declare (type fixnum length n))
  (let ((vector (make-array length)))
    (dotimes (i length)
      (setf (svref vector i) (cons nil nil)))
    (dotimes (i n)
      (setf vector (copy-vector vector)))))

(defun main (&aux (n (second sb-ext:*posix-argv*))
                  (length (third sb-ext:*posix-argv*)))
  (when (> (length sb-ext:*posix-argv*) 3)
    (write-line "Usage test_sbcl [ n [ length ] ]")
    (sb-ext:quit :unix-status 1))
  (let ((n (or (and n (parse-integer n))
               1000000))
        (length (or (and length (parse-integer length))
                    100)))
    (declare (type fixnum n length))
    (test n length))
  (sb-ext:gc :full t))

(sb-ext:save-lisp-and-die "test_sbcl"
                          :executable t
                          :toplevel #'main)

Крестовый код собирать так: gcc -O2 -o test_cpp test_cpp.cxx

#include <cstdlib>
#include <vector>
#include <iostream>
#include <memory>

struct Cons
{
    void* car;
    void* cdr;
    Cons(void* _car, void* _cdr)
    {
        car = _car;
        cdr = _cdr;
    }
};

typedef std::shared_ptr<Cons> ConsPtr;
typedef std::vector<ConsPtr> ConsPtrVector;
typedef std::shared_ptr<ConsPtrVector> ConsPtrVectorPtr;

ConsPtrVectorPtr CopyVector(ConsPtrVectorPtr vec)
{
    int length = vec->size();
    ConsPtrVectorPtr copy(new ConsPtrVector(length));
    for(int i = 0; i<length; ++i)
    {
        (*copy)[i]  = (*vec)[i];
    }
    return copy;
}

void Test(int n, int length)
{
    ConsPtrVectorPtr vec(new ConsPtrVector(length));
    for(int i = 0; i<length; ++i)
    {
        ConsPtr ptr(new Cons(NULL, NULL));
        (*vec)[i] = ptr;
    }
    for(int i = 0; i<n; ++i)
    {
        ConsPtrVectorPtr copy = CopyVector(vec);
        vec.swap(copy);
    }
}

int main(int argc, char** argv)
{
    int n = 1000000, length = 100;
    switch(argc)
    {
        case 1:
            break;
        case 2:
            if((n = atoi(argv[1])) <= 0)
            {
                std::cout << "Invalid parameter: " << argv[1] << std::endl;
                return 1;
            }
            break;
        case 3:
            if((n = atoi(argv[1])) <= 0)
            {
                std::cout << "Invalid parameter: " << argv[1] << std::endl;
                return 1;
            }
            if((length = atoi(argv[2])) <= 0)
            {
                std::cout << "Invalid parameter: " << argv[2] << std::endl;
                return 1;
            }
            break;
        default:
            std::cout << "Usage: test_cpp [ n [ length ] ]" << std::endl;
            return 1;
    }
    Test(n, length);
    return 0;
}

Код на C# собирать примерно так: dotnet publish -c Release -r linux-x64 -p:PublishSingleFile=true --self-contained true -o ./ TestCsharp.csproj

namespace TestCSharp
{
    public record Cons(object? Car, object? Cdr);

    public static class Program
    {
        public static Cons[] CopyVector(Cons[] vec)
        {
            var len = vec.Length;
            var copy = new Cons[len];
            for (var i = 0; i < len; i++)
            {
                copy[i] = vec[i];
            }
            return copy;
        }

        public static void Test(int n, int length)
        {
            var vec = new Cons[length];
            for (var i = 0; i < length; i++)
            {
                vec[i] = new Cons(null, null);
            }

            for (var i = 0; i < n; ++i)
            {
                var copy = CopyVector(vec);
                vec = copy;
            }
        }

        public static int Main(string[] args)
        {
            int n = 1000000, length = 100;

            switch (args.Length)
            {
                case 0:
                    break;
                case 1:
                    n = int.Parse(args[0]);
                    break;
                case 2:
                    n = int.Parse(args[0]);
                    length = int.Parse(args[1]);
                    break;
                default:
                    Console.Error.WriteLine("Usage: test_csharp [n [length]]");
                    return 1;
            }
            Test(n, length);
            return 0;
        }
    }
}

Результат такой, ггг:

lovesan@ubuntu:~$ time ./test_sbcl 1000000 1000

real    0m1.077s
user    0m1.047s
sys     0m0.030s
lovesan@ubuntu:~$ time ./TestCSharp 1000000 1000

real    0m2.312s
user    0m2.264s
sys     0m0.010s
lovesan@ubuntu:~$ time ./test_cpp 1000000 1000

real    0m3.233s
user    0m3.228s
sys     0m0.000s

То есть, кресты в ТРИ раза медленнее лиспа, и при этом в полтора раза медленнее C#. И в реальных системах, так и происходит. Даже еще хуже. Кто с крестами работал, и с крестолюбцами, тот в цирке не смеется.

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

Даже еще хуже. Кто с крестами работал, и с крестолюбцами,

Я работал в ПФР с крестолюбцем.

Сам я на плюсах кодил только в юности лет 30 назад, тогда выбор был не шибко большой, но даже тогда уже было очевидно, что Clipper CA 5.01 для разработки прикладнухи продуктивнее раз в 100.

Сейчас это было бы что-то похожее на https://www.xsharp.eu/

тот в цирке не смеется.

И как раз в цирке.

Так что вообще не смешно совсем …

Он даже отчётные формы в Excel готовил через Excel ActiveX интерфейс + Visual C++

sanyo1234
()
Последнее исправление: sanyo1234 (всего исправлений: 6)
Ответ на: комментарий от lovesan

То есть, кресты в ТРИ раза медленнее лиспа, и при этом в полтора раза медленнее C#. И в реальных системах, так и происходит. Даже еще хуже. Кто с крестами работал, и с крестолюбцами, тот в цирке не смеется.

Легким движением руки:

void Test(std::size_t n, std::size_t length)
{
    ConsPtrVectorPtr vec = std::make_shared<ConsPtrVector>();
    vec->reserve(length);
    for(std::size_t i = 0; i<length; ++i)
    {
        vec->push_back(std::make_shared<Cons>(nullptr, nullptr));
    }
    for(std::size_t i = 0; i<n; ++i)
    {
        ConsPtrVectorPtr copy = std::make_shared<ConsPtrVector>(*vec);
        vec.swap(copy);
    }
}

и

$ time ./lavsan 1000000 1000

real    0m3,568s
user    0m3,564s
sys     0m0,004s

$ time ./make_shared 1000000 1000

real    0m2,690s
user    0m2,687s
sys     0m0,004s
eao197 ★★★★★
()
Ответ на: комментарий от lovesan

Зачем ты меняешь суть программы?

Программа делает тоже самое, что и исходная. Но быстрее, и код компактнее.

Ты не понял, про что тест?

Про стоимость динамической аллокации и деаллокации памяти. Ну так она никуда и не делась.

Было бы интересно другое. Вот некто lovesan сказал:

Синтетические тесты в вакууме - говно на палочке

А потом этот же lovesan бах! И синтетический тест в качестве доказательства.

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

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

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

То есть, кресты в ТРИ раза медленнее лиспа,

для начала в с++ убери SharedPtr для указателя на cons пару, потому, что это тряхом… есть указатель со счетчиком ссылок, а не просто указатель как в лиспе или шарпе.

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

Cons-ячейка здесь должна быть объектом в памяти, который доступен через указатель. Не важно что это тут она такая простая. В реальности это может не ячейка, а какая-нибудь хитрожопая херота, типа графа объектов HTML нодов где-нибудь внутри вебкита. И соответственно, проход по вектору тут эмулирует сложные случаи доступа к сложным объектам, а не копирование, блять, вектора, как вон этот выпускник бобруйского государственного по-глупости подумал.

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

ConsPtrVectorPtr copy(new ConsPtrVector(length));

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

в лиспе наверняка такого не будет. про шарп не знаю.

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

Честный вопрос: сколько в крестах таких магических штук, работающих быстрее наивного кода, и сколько лет опыта нужно, чтобы на гора выдавать код, сопоставимый (как показывает пример от eao) с наивным кодом на шарпе?

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

использование shared_ptr в данном случае - это антипаттерн. тут надо использовать обычный указатель, как это будет в лиспе.

shared_ptr - это управление ресурсом на основе счета ссылок. тут это вообще не надо.

использование векторов - тоже не надо. по крайней мере в лисповом коде это похоже просто массив. вот и используй массив и тут.

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

Честный вопрос: сколько в крестах таких магических штук

В приведенном примере нет никаких магических штук. За реально магическими штуками нужно, например, вот сюда.

Здесь достаточно просто понимания того, как работает std::vector. И чем отличается std::shared_ptr<T> a{new T()} от std::shared_ptr<T> a = std::make_shared<T>().

ИМХО, для C++ника такое понимание необходимо. Если только он не Qt-шный формошлепщик.

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

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

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

Но если туп как дерево, родишься баобабом и будешь баобабом тыщу лет пока помрёшь.

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

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

Он не каких-то магических штук добавил, он тупо удалил часть логики, демонстрирующей суть.

Какую такую часть? Все объекты создаются динамически, все компирования происходят, все swap-ы выполняются.

Покажи пальцем что куда пропало. Если сможешь, конечно.

Про сложные структуры данных, работу с ними, и их менеджмент.

Все это осталось на своих местах.

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

замена плюсовой строчки:

typedef std::shared_ptr<Cons> ConsPtr;

на

typedef Cons* ConsPtr;

дала такой эффект - с шаред_поинтером

.....:~..../test$ time ./test 10000000 100
real    0m5,607s
user    0m5,601s
sys     0m0,004s

с просто поинтером

.....:~..../test$ time ./test 10000000 100
real    0m1,671s
user    0m1,666s
sys     0m0,004s

итого 3 с хвостиком раз. побиты и лисп и шарп. это мы еще вектора не трогали.

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

Нео, проснись, ты обгадился. В том коде ты тестируешь саллокаторы памяти, системный из libc vs GC-шный, а не ЯП-ы. Измени аллокатор для кода на плюсах, запили простейший велосипедный на пуле обьектов, результат сравняется или превзойдет другие. Начнешь кочевряжиться про оптимизации, добавишь себе очков неосилятора

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

А что с этим тестом?

Не смотрел на конкурентную версию. Но если в однопоточной заменить использование .at() в do_work на обычный operator[], то у меня время исполнения для 5k падает с 30ms до 28ms.

Кроме того, в структуре RelatedPosts, какая-то странная пессимизация: зачем-то хранятся отдельные указатели на id и на tags, хотя можно было бы сохранить всего один указатель на исходный Post. На 5k выигрыша в производительности это не дает, но память экономит.

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

Что это меняет?

Если говорить про ваше поведение, то тупизм и нежелание нормально отвечать на вопросы, меняет отношение к вам с нейтрального до «малолетний дебил» (с)

Хотите, чтобы с вами общались нормально, так ведите себя нормально.

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

Если говорить про ваше поведение, то тупизм и нежелание нормально отвечать на вопросы, меняет отношение к вам с нейтрального до «малолетний дебил» (с)

Так ведь это к вам в первую очередь относится.

К чему эта ваша попытка:

время исполнения для 5k падает с 30ms до 28ms.

улучшить производительность на 6%?

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

улучшить производительность на 6%?

К тому, что в коде есть явные места с пессимизаций.

Если вы посмотрите на результаты для Rust Concurrent и C++ concurrent в своей же таблице выше, то там разница всего 9%.

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

Если вы посмотрите на результаты для Rust Concurrent и C++ concurrent в своей же таблице выше, то там разница всего 9%.

IMHO вот это лидерство «я первый, быстрее на 1%» - это для детского сада. В первую очередь важны комплексные характеристики проекта, включая его безглючность, поддерживаемость, и т.п. А C++ по этим параметрам обычно проигрывает Шарпу многократно, и чем сильнее недофинансирование проекта, тем в большей степени это проявляется.

А разброс производительности в пределах +-10-30% вообще ни о чём для большинства проектов.

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

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

Пожалуйста, хватит бла-бла-бла. Я вам выше несколько вопросов задал. Вы собираетесь на них ответить?

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

О, так поциент еще и читать не умеет. Ясно, понятно.

Сами то давно проверялись или вообще ни разу? (ведь абсолютно здоровых нет, есть только недообследованные):

Нарциссизм в психологии рассматривается как психическое отклонение, которое проявляется в преувеличенном мнении о собственной важности и уникальности, а также в стремлении к постоянному восхищению и подтверждению своего превосходства над другими. Это состояние может быть частью нарциссического расстройства личности (НРЛ), которое характеризуется убежденностью в собственной уникальности, особом положении и превосходстве над окружающими. Нарциссы обычно имеют высокие притязания, стремление к лидерству и могут использовать манипуляции для достижения своих целей. Отношения с нарциссом могут быть сложными из-за его склонности к идеализации и обесцениванию окружающих, а также из-за недостатка эмпатии и уважения к другим людям
sanyo1234
()
Последнее исправление: sanyo1234 (всего исправлений: 1)
Ответ на: комментарий от sanyo1234

Брошу в Вашу копилочку пяточёк.

В gcc имеется goto <Выражение>, а у Microsoft этого нет.
За дураков нас держат.
Не исключаю, что такой пассаж сделан для того, чтобы другим было сложнее писать хороший код.

goto <Выражение> это же мои любимые таблицы решений, которые Microsoft у меня отобрала.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 2)
Ответ на: комментарий от alysnix

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

https://github.com/jinyus/related_post_gen

В первом случае результаты плюсов и шарпа почти одинаковые, а для multicore шарп вроде бы как почти лучший, не считая Dlang?

В тесте Time (5k posts) C# и вовсе абсолютный лидер!

C# Concurrent (AOT) 4.33 ms

Multicore Results

LanguageTime (5k posts)20k posts60k postsTotal
D Concurrent (v2)5.81 ms44.68 ms262.69 ms313.19 ms
C# Concurrent (JIT)7.55 ms45.08 ms369.55 ms422.17 ms
C# Concurrent (AOT)4.33 ms51.95 ms389.07 ms445.35 ms
D Concurrent7.09 ms61.79 ms452.55 ms521.43 ms
Rust Concurrent4.66 ms56.88 ms492.16 ms553.71 ms
C++ Concurrent5.10 ms68.67 ms558.33 ms632.10 ms
Nim Concurrent5.32 ms68.15 ms568.41 ms641.88 ms
Go Concurrent5.82 ms77.11 ms637.31 ms720.24 ms
Julia Concurrent6.03 ms89.56 ms665.41 ms761.00 ms
F# Concurrent8.50 ms99.67 ms875.67 ms983.83 ms
Swift Concurrent10.69 ms119.00 ms986.94 ms1.12 s
F# Concurrent (AOT)8.50 ms128.33 ms1.13 s1.27 s
Java Concurrent (JIT)58.00 ms183.33 ms1.15 s1.39 s
Numba Concurrent19.67 ms173.20 ms1.28 s1.47 s
Java (GraalVM) Concurrent12.00 ms182.33 ms1.50 s1.69 s
sanyo1234
()
Последнее исправление: sanyo1234 (всего исправлений: 6)