В статье Наблюдение за выполнением конкурирующих задач в Go и Rust коллега cpmonster привёл весьма интересные результаты: Ну, в 1.5 раза… Ну, в 2 раза… Но семь гвардейцев за два дня🎦 — это слишком, тем более что тут "гвардейцев" больше восьми! Или нет, не слишком? В общем, потенциал любопытства пересилил другие потенциалы и я провёл своё исследование. Для начала попробуем воспроизвести результаты. Нужны исходники, а также Go и Rust (у меня версии 1.18 и 1.61, соответственно). Идём в папку go/src и запускаем go run concgo.go s: Теперь в папке rust выполним cargo run s: Надо же, производительность версии на Rust в три раза ниже, чем версии на Go!  А, нет — это же debug, вот так надо: cargo run --release s. Совсем другое дело: Да, всё повторилось, те же 8+ раз. У меня и до чтения рассматриваемой статьи сложилось мнение, что Rust "готовит" более быстрые "числодробилки", но полученный результат — это же настоящее "унижение" для Go. Да неужто все именно так?! Будем разбираться. Смотреть сюда: Именно эти функции вычисления последовательности триплетов подвергаются испытаниям. При запуске с ключом s испытание происходит в функции count_cycles_per_sec(). Испытание, надо заметить, происходит "вне конкуренции" — т.е. в одном потоке. Что, конечно, сильно упрощает анализ. Сам автор статьи приводит такое соображение: В принципе, да. Значения переменных в Go легко и зачастую незаметно "убегают в кучу", именно с этого я и начал свои эксперименты: Нет, тут все чисто: Версия из комментариев: На Go 1.18 результаты не лучше. Несколько раз высказывались сомнения в корректности испытаний, по типу такого: Всё это интересно, но запуск в режиме go run concgo.go s ведёт к тестированию всего лишь в одном потоке, так что феномен проявляется и может быть изучен без привлечения горутин и tokio. С ключами оптимизации у компилятора Go негусто, скорее есть ключи "деоптимизации" (-l -N) — так что остаётся работать с исходными текстами. Сравнение текстов показало, что тип Triplet в Rust объявлен как кортеж (tuple): В то время как для Go используется массив: В Go более близким к кортежу типом является структура: При помощи чудесного инструмента godbolt посмотрим, есть ли разница в ассемблерном коде для работы с такими определениями: Оказывается, разница есть: То есть работа со структурой происходит через регистры, а с массивом фиксированной длины — через стек. Это, конечно, может повлиять на производительность! Я сделал fork оригинального репозитория, в нём папочку go2/src, переопределил Triplet. Результат работает так: Разница теперь всего в 3 гвардейца, уже не так обидно. Смотрим в ассемблер функций iterate(): Go встраивает вызов get_next_triplet(), но не делает этого для is_convergent(): А вот Rust полностью оснащает iterate.asm встроенной вычислительной техникой. Внешними остались только вызовы типа call std::io::stdio::_print, но они на скорость не влияют, так как последовательность не сходится и условие is_convergent(triplet, next_triplet) никогда не выполняется. Отсюда и разница. Для дальнейшего повышения производительности версии Go функцию is_convergent() можно встроить вручную: Получилась папка go3/src, запуск из нее: Все равно 1.5 гвардейца, и это при том, что все вычисления встроены, см. go3/src/iterate.asm. В качестве вишенки на торте попробуем переопределить Tripletв версии для Rust таким образом: Будет ли разница? Нет. Ассемблер раз: Ассемблер два: