LINUX.ORG.RU

Golang в Revel и Gin-gonic почему-то работает медленнее PHP :-/

 , , , ,


0

1

Фигня какая-то. Делаю тут для изучения несложную задачку (взять html, подсунуть параметр из GET-запроса) на Golang. В результате, запросов в секунду:

* PHP (голый) — до 12000
* Golang/Revel — до 8700
* Golang/Gin-gonic — до 4800

Удивительно, во-первых, что Revel быстрее Gin'а, обычно считается наоборот. Но это ладно.

Вот каким макаром PHP получается быстрее — не понимаю. Т.е. цифра вообще какая-то нереальная в моём привычном мировоззрении... При чём не 7.0 какой-нибудь или hhvm, а обычный 5.4.45, fpm.

Может, фишка в том, что PHP используется классически, html-код со вставкой, который один раз компилируется и потом берётся из кеша, а golang-фреймворки так не умеют и производят чтение/парсинг на каждом запросе? Или вопрос в оптимизации многоядерности, т.к. у php-fpm уйма инстансов, грузящих все ядра, а у Revel/Gin собственный менеджер и фиг знает, как он там распределяет загрузку?

★★★★★

Например, у php гораздо быстрее регэкспы, чем в go.

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

Например, у php гораздо быстрее регэкспы, чем в go.

Там всего один, совсем простой регексп. Он, по идее, занимает совсем доли процента загрузки на общем фоне :)

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

подозреваю, что html/template может быть тоже не образцом оптимизированности. Можешь погуглить альтернативные реализации того и другого. Маршалинг-анмаршаллинг json, например, в альтернативных реализациях быстрее, чем в стандартной библиотеке.

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

Он, по идее, занимает совсем доли процента загрузки на общем фоне :)

Профилируй, чтобы не гадать на кофейной гуще.

feofan ★★★★★ ()
Последнее исправление: feofan (всего исправлений: 1)

А голый Go? Выложи примеры своего кода куда-нибудь. А то так — это гадание на кофейной гуще.

По хорошему ты парзишь templates только одни раз, а потом только используешь. Так же с regex (если они вообще нужны).

Но если же конечно при каждом запросе в обработчике парзить всё по новой — то ничего удивительного.

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

А голый Go?

Ну, логика подсказывает, что голый Go будет куда быстрее :)

Сейчас проверил, Gin без парсинга html выдаёт до 12 r/s, как и PHP.

Выложи примеры своего кода куда-нибудь.

Да там кода-то... Вот пример с Gin: https://gist.github.com/Balancer/54d6d3dff3139608e423

Вот контроллер Revel:
https://gist.github.com/Balancer/5ab4b97249af7d449522

KRoN73 ★★★★★ ()

Попробуй в коде перед запуском сервера сказать

runtime.GOMAXPROCS(4);

До 1.5 Golang работал на одном ядре по-умолчанию, а это выставит 4 штуки.

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

Попробуй в коде перед запуском сервера сказать

Я в коде Gin играл с этим (в коде на gist как раз стоит один из вариантов) — не влияет. Переменную окружения GOMAXPROCS тоже пробовал ставить в 10 (на машине, вообще, 24 ядра) никакого эффекта.

go 1.5.1

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

Про примерс gin: во-первых, зачем компилировать regexp при каждом запросе? во-вторых, про небыстрый json из стандартной библиотеки я уже говорил, но думаю, тут дело не в нем. Ссылку как профилировать я дал.

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

Про revel то же самое: сделай rp глобальной переменной, чтобы твой регэксп был скомпилирован до запроса.

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

во-первых, зачем компилировать regexp при каждом запросе?

На скорости не сказывается.

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

Да, я делал пример с прямым возвратом строки:

package main

import "github.com/gin-gonic/gin"
import "runtime"
import "net/http"

func main() {

    runtime.GOMAXPROCS(runtime.NumCPU())

    router := gin.Default()
    router.GET("/chart/1000.php", func(c *gin.Context) {
            c.String(http.StatusOK, "Hello world")
    })

    router.Run("127.0.0.1:18080")
}


Он выдаёт до 12000 rps в nginx-бэкенде и столько же при прямом запросе по 127.0.0.1 и очень-очень редко — выбросы до 14-16 тыс. rps. На фоне регулярных 12000 rps у PHP — мало.

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

конпеляция регэкспа на каждый запрос

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

Есть подозрение, что ты не понимаешь, что измеряешь. Это производительность чего?

Нет смысла писать на го как на пхп.

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

Ну и, если уж так тупо в лоб измерять, сколько памяти отжирает при этом го и сколько пхп?

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

Это производительность чего?

Простых запросов.

Нет смысла писать на го как на пхп.

Ну так как мне написать более быстрый вариант? :)

Задача простая — есть html-шаблон. Нужно проставить вычисленные значения и вернуть результат.

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

Ну и, если уж так тупо в лоб измерять, сколько памяти отжирает при этом го и сколько пхп?

Не важно в моём случае. Всё равно 256Гб.

Я прекрасно понимаю, что на сложной задаче или с числодробилками Go уделает PHP. Я не понимаю, почему скорость одного порядка на простой задаче :)

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

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

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

как мне написать более быстрый вариант? :)

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

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

Задача простая — есть html-шаблон. Нужно проставить вычисленные значения и вернуть результат.

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

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

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

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

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

Я не понимаю, почему скорость одного порядка на простой задаче :)

Дык, может оно в сетку уперлось?

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

Вынеси в обоих случаях

rp := regexp.MustCompile("[^A-Z]+")
на верхний уровень (в global или в main) и проверь ещё раз.

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

На PHP код тоже хотелось бы взглянуть.

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

Можно попробовать в релизе

gin.SetMode(gin.ReleaseMode)
Плюс fmt.Printf убрать, если не сильно нужен, ввод-вывод в го по умолчанию не буферизован.

netrino ()

А кто тебе сказал что PHP должен быть медленным?

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

интерпретатор вс компилятор
динамичекие типы вс статические

Bad_ptr ★★★★ ()

Gin сам по себе не очень фреймворк. Ребята ушли на учебу и забросили его. Шаблоны в самом Golang не очень то и быстрые.

Рекомендую взять echo а для шаблонов pongo2 (в нем как раз и кеширование есть).

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

в нем как раз и кеширование есть

Оно из коробки есть:

var tmpls = template.Must(template.ParseGlob("./templates/*"))
func getIndex(c *gin.Context) {
	tmpls.ExecuteTemplate(c.Writer, "index.tmpl", nil)
}
func main() {
	app := gin.Default()
	app.GET("/", getIndex)
	log.Fatal(http.ListenAndServe(":8080", app))
}

anonymous ()

А тут и не должен го быть быстрее, го будет на порядок быстрее в real world задачах, где тебе нужно держать коннекты, на пхп много процессов ненаплодишь, а так ты меряешь как сишечка внутри пхп работает на реквестах.

umren ★★★★★ ()

И да, цифры у Go для такого сервера откровенно маленькие, у меня тоже самое на десктопе не первой свежести.

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

ведь эти фреймворки никто толком не использует, сколько там граблей раскидано неизвестно.

Да, с документацией там швах. Час, наверное, ковырялся, прежде чем получилось что нужно было. И из этого часа 3/4 — гугление.

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

Дык, может оно в сетку уперлось?

Может быть (хотя оно на локалхосте, но там тоже много ограничений). Завтра/послезавтра продолжу разбираться с оптимизациями.

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

Вынеси в обоих случаях

Там я приводил пример вообще без регекспа и парсинга шаблонов :)

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

На PHP код тоже хотелось бы взглянуть.

Там совсем смотреть не на что:

<?php
    $type = empty($_GET['id']) ? 'EURUSD' : strtoupper(preg_replace('/\W/', '_', $_GET['id']));
?>
<!DOCTYPE html>
<html>
<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
...
<iframe ... src="http://...?type=<?=$type?>" ... >
...
</body>
</html>

KRoN73 ★★★★★ ()

Слышал, что в Revel много магии на рефлекшне. Может быть поэтому тормозит? Попробуй без Revel-а, в стандартной библиотеке Go есть поддержка HTTP, простой API для написания обработчиков и шаблонизатор.

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

Плюс fmt.Printf убрать

Это моя опечатка :) Он в коде закомментирован, а я, выкладывая в gist тормознул и не строчку стёр (чтобы не мешалась), а комментарий :)

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

А кто тебе сказал что PHP должен быть медленным?

Объектный Фибоначчи :)

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

Рекомендую взять echo а для шаблонов pongo2 (в нем как раз и кеширование есть).

Спасибо, посмотрю.

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

а так ты меряешь как сишечка внутри пхп работает на реквестах

Скорее измеряю, как PHP рождается и умирает. Это же одна из самых громких претензий к классическому PHP. А тут оказывается, что рождающийся и умирающий PHP не уступает живущему Go. Это и удивило.

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

Слышал, что в Revel много магии на рефлекшне. Может быть поэтому тормозит?

Если бы тормозил Reval, это бы меня не удивило. Удивило, что куда более лёгкий Gin у меня работает медленнее.

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

А тут оказывается, что рождающийся и умирающий PHP не уступает живущему Go. Это и удивило.

Ты ведь сам понимаешь что невозможно с моделью process per request соревноваться с демонизированным веб сервером, который еще и легкие потоки умеет. Бенчмарки сломаны.

umren ★★★★★ ()

В общем, на упомянутом сервере nginx статику отдаёт со скоростью до 16 тыс rps что явно мало. С сетевыми настройками разбираться будут позже, а вот результаты теста на домашней машине с Gentoo.

— nginx/статика: 26 krps
— php-fpm-5.6.17/hello world: 15 krps
— go-1.5.3/gin/hello world: 20 krps

Тут go шустрее. Но php всё равно поражает. Я как-то привык к тому, что hello world отдаётся на порядок медленнее статики nginx. А тут получается тот же порядок.

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

Ты ведь сам понимаешь что невозможно с моделью process per request соревноваться с демонизированным веб сервером

Понимаю. И потому крайне удивлён, что php с его идеологией совсем немного отстаёт от статики nginx :)

KRoN73 ★★★★★ ()

Версия go какая? Если меньше 1.5, то без runtime.GOMAXPROCS(runtime.NumCPU()) он жрёт только одно ядро и с многоядерностью были проблемки. В 1.5 пофиксили.

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

А чего тут поражать в php 5.6 встроенный opcache. Компиляции на каждый запрос не происходит, просто выполняется код, который к тому же берется из памяти.

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

nikita-b ()
Ответ на: комментарий от nikita-b

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

ab -n10000 -c100 :)

Коды на разных языках, версии программного обеспечения и т.д.

Это было.

конфиги серверов

Одинаковые внутри одного эксперимента.

KRoN73 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.