image Добро пожаловать, или Посторонним вход воспрещён
(С) Э.Г.Климов 1964


Написанный на языке Go роутер (или как его ещё иногда называют — маршрутизатор), который оказался достаточно быстрым для того, чтобы его не стыдно было сравнить с лидерами go-роутинга: Bone, Httprouter, Gorilla, Zeus. Название роутеру дало простое русское слово «Вход», набранное английскими буквами в кодировке волапюк en.wikipedia.org/wiki/Volapuk_encoding



Никогда со мной такого не бывало: нет входа! Куда ни ткнись — везде сплошные окна.
(С) Аркадий и Борис Стругацкие. Хромая судьба


Bxog (английские буквы), читается как Бииксоуджи. В комментариях предлагаю называть роутер на выбор: Вход, Bxog, Бииксоуджи, Биксодж. Для модуля в приложении, которое первым встречает запрос пользователя, название, с моей конечно точки зрения, вполне подходящее. По аналогии с Windows хотелось бы назвать свой роутер Door, но боюсь быть неверно понятым ;)
Ссылки на исходники:
github.com/claygod/Bxog
github.com/claygod/BxogTest

Зачем

И нафига мне эти перья?
(С) Из анекдота


Скажу сразу, во всём виноват кризис: зарплаты не хватает, с Адсенса на старых сайтах ничего уже не капает, а жить надо. Нужен дополнительный заработок, а на чём его делать? На пыхе надоело, а на другом ничего не умею, ну не идти же в самом деле, в верстальщики… Фронтэнд, это как-то не моё.

Изначально я приглядывался к С/С++, притом скорее склонялся к Си (тут каждому своё). Но учитывая указатели, указатели на указатели, указатели на функции и указатели на функции, которые принимают на вход указатели на функции, мой неокрепший мозг потребовал вернуться от безалкогольного пива к классическому, чему как-то воспротивился организм (единство и борьба противоположностей).

После приятного и интересного Lua под руку попался новый (для меня) Golang: простой, быстро осваеваемый, похожий на Си. Поставил LiteIDE, и можно работать. Важный плюс — на рабочий компьютер под виндой всё можно поставить даже с правами пользователя (ну строгие корпоративные правила у меня на работе, это факт).

Осталось определиться с тем, что писать в процессе изучения языка (я считаю, что по другому язык нормально никак не изучить). Фреймворк, это как-то многовато… А если изучать даже всего по одному языку в год, это ж сколько фреймворков придётся наклепать? Боюсь, планета такого не выдержит, я ведь на ней не один :) Решил написать роутер, и на этом, пожалуй, лирическое отступление закончу.

Разработка

Поскольку языка Go на момент начало разработки я ещё не знал, то и структура роутера, и принципы его хранения и поиска маршрутов менялись несколько раз (кардинально, раза четыре). Первая итерация была совершенно ознакомительной. Посмотрев на неё (со слезами, а как же), я уяснил основы Golang и сделал вторую версию, в которой даже на код глядеть было не слишком страшно. Однако даже простое ab тестирование показало мне, что моя поделка довольно тормознутая.

Поменяв алгоритмы и внеся ещё некоторые правки, я решил ознакомиться с другими Go-роутерами. Из списка мне понравился Bone, не удивлюсь, если во многом из-за названия и прикольной картинки. Посмотрев на этот роутер я подумал, что эх, мне бы так смочь… Количество звёзд под тысячу у этого роутера тоже как-то воодушевляли.

У Bone есть бенч, который толкнул-таки меня на третью итерацию разработки своего творения. Написав себе похожий бенч, я опять поменял структуру хранения и алгоритм поиска. Теперь, о чудо, мой Биксоджей смог обогнать Gorilla Pat (Gorilla Mux более медленный, и с ним тягаться не сложно). Одновременно я понял, что любимец Bone совсем не заточен под большие динамические урлы, хотя неплохо справляется с короткими статическими, и его бенч как раз под это и написан.

Король умер, да здравствует король! Теперь я буду сражаться с HttpRouter. По ходу пьесы я уяснил, что мапы в Go мягко говоря не блещут скоростью по сравнению с массивами. Очередной виток разработки начал выводить роутер на финишную прямую, где бенч лидера стал близок, можно сказать соседским. Отстранёно взглянув на свой код, я решил, что он слишком многословен, и кроме того, требует тонкой настройки.

Отшлифовав роутер на столько, на сколько хватило терпения и мозгов, я перешёл к написанию тестов (каюсь, до этого просто тестировал вручную и эпизодически). Тесты показали, что и терпения и мозгов у меня не так уж и много, а заодно вскрыли пару крупных и неявных ошибок, которые пришлось устранять.

Поскольку strings.Split оказалась тоже не из быстрых, при колеблющемся свете свечи пришлось написать аналог, удовлетворяющий моим требованиям. Да скажу честно, иногда писать быстрый код означает писать не очень красивый и хардкорный код. Лес рубят — щепки летят. В конечном итоге я смог в бенчах добиться превосходства над королём. Это немного польстило моему самолюбию, и хотя и не ставилось явной целью.

Быстрый старт

В принципе, я постарался организовать код так, чтобы работа роутера была проста и понятна, т. е. надеюсь, код говорит сам за себя. Ну а ниже даю комплексный пример использования роутера, демонстрирующий все его методы
комплексный пример использования роутера
package main

import (
	"io"
	"net/http"
	"github.com/claygod/Bxog"
)

// Handlers
func IHandler(w http.ResponseWriter, req *http.Request, r *bxog.Router) {
	io.WriteString(w, "Welcome to Bxog!")
}
func THandler(w http.ResponseWriter, req *http.Request, r *bxog.Router) {
	params := r.Params(req, "/abc/:par")
	io.WriteString(w, "Params:\n")
	io.WriteString(w, " 'par' -> "+params["par"]+"\n")
}
func PHandler(w http.ResponseWriter, req *http.Request, r *bxog.Router) {
	// Получить параметры из урла
	params := r.Params(req, "country")
	io.WriteString(w, "Country:\n")
	io.WriteString(w, " 'name' -> "+params["name"]+"\n")
	io.WriteString(w, " 'capital' -> "+params["city"]+"\n")
	io.WriteString(w, " 'valuta' -> "+params["money"]+"\n")
	// Сгенерировать строку урла
	io.WriteString(w, "Creating a URL from route:\n")
	io.WriteString(w, r.Create("country", map[string]string{"name": "Russia", "capital": "Moscow", "money": "rouble"}))
}

// Main
func main() {
	m := bxog.New()
	m.Add("/", IHandler)
	m.Add("/abc/:par", THandler)
	m.Add("/country/:name/capital/:city/valuta/:money", PHandler).
		Id("country"). // Для удобства короткий ID
		Method("GET") // Тут GET можно было не указывать, это для примера
	m.Start(":80")
}



После запуска приведённого примера перейдите по ссылкам:


Конфигурирование

Настраивать роутер нужно через редактирование файла конфигурации github.com/claygod/bxog/config.go В файле обозначены константы, которые можно изменять.

HTTP_METHOD_DEFAULT
Метод, используемый роутером по умолчанию (GET, POST etc.). Эта опция позволяет писать меньше кода и по сути просто сахар.

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

HTTP_PATTERN_COUNT
Максимальная длина урла. Тут понятно без объяснений.

READ_TIME_OUT
Максимальное время ожидания при чтении

WRITE_TIME_OUT
Максимальное время ожидания при записи

FILE_PREF
Локальный путь от корня сайта в урле для файлов, доступных для скачивания.

FILE_PATH
Полный путь к каталогу, из которого файлы будут доступны для скачивания.

Бенчмарк

Роутер получился достаточно быстрым для того, чтобы было не стыдно испытать его в бенчмарке совместно с такими популярными роутерами, написанными на Go, как Bone, Httprouter, Gorilla, Zeus.Код бенчмарка и тесты роутера лежит тут — github.com/claygod/bxogtest

Результат бенчмарка для указанных роутеров в сравнении с Bxog со 150 сгенерированными 6-секционными роутами (конфигурацию компьютера не указываю, ибо тут скорее важны не абсолютные цифры, а их сравнение):

  • BenchmarkBxogMux-4 5000000 330 ns/op
  • BenchmarkHttpRouterMux-4 3000000 395 ns/op
  • BenchmarkZeusMux-4 100000 23772 ns/op
  • BenchmarkGorillaMux-4 50000 30223 ns/op
  • BenchmarkGorillaPatMux-4 1000000 1253 ns/op
  • BenchmarkBoneMux2-4 20000 63656 ns/op

Очень порадовал Gorilla Pat, который демонстрирует хорошую, хотя и не лучшую производительность. Если вас устраивают программы от Gorilla, то для поиска быстрого решения Gorilla Pat очень хорошее решение.
Если же говорить о выборе роутера вообще, то тут немаловажным будет то, насколько он подходит вам изнутри (это моё мнение, кто-то считает, что кроме API ничего глядеть и не надо). Но то, что есть выбор, это уже хорошо. На картинке ниже видно, что у тройки лидеров в зависимости от количества маршрутов скорость сильно не меняется.

image

Тесты

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

API

API у роутера простое, как апельсин. В качестве небольшой сладости (если апельсин кислый), добавлена возможность не только обращаться к параметрам из урла в хэндлере, но и генерировать новый урл. Это может оказаться удобным при разработке сайта на Go (или фреймворка под такие задачи).

Методы:
  • New — создать мультиплексор
  • Add — добавить роут. По умолчанию метод GET, и ID роута в виде строки его правила, соответственно, это не обязательные опции. Пример с указанием метода и ID: m.Add("/abc/:param", YourHandler).Method(«POST»).Id(«abc»)
  • Start — запустить сервер с указанием порта, который нужно слушать
  • Params — получить из URL параметры
  • Create — создать URL из параметров роута
  • Test — аналог Start (только для тестирования)

Простой пример:
	m := bxog.New()
	m.Add("/", IndexHandler)
	m.Start(":80")


Секции

Как уже упоминал выше, урл слэшами делится на секции. Секция может быть статическая (неизменяемая) и динамическая (аргумент). Динамическая секция начинается с двоеточия (это общеупотребительная практика роутеров). Последняя секция не должна заканчиваться на слэш.

Статические файлы

С помощью констант FILE_PREF и FILE_PATH необходимо указать роутеру, по какому пути будут доступны статические файлы в браузере и какой путь к этим файлам на жёстком диске.

Golang

Споры о Go не утихают. Одни его критикуют, другие хвалят. И то, и другое, возможно, обосновано. Мне понравилось принудительное форматирование кода: чтение чужих исходников теперь не вызывает никаких проблем, всё однородно и читаемо. Иногда мешают напоминания о созданных и не использованных переменных, но в конечном итоге, просто меняешь свой стиль программирования, чтобы компиляция сразу прошла успешно. Буду ли я в дальнейшем использовать этот язык? Да. Посоветую ли его другим? Да. Нужно ли его делать главным и единственным языком в своей работе? Нет, и не потому, что он плохой, просто свой кругозор надо расширять.

Подытоживая

Вот все пишут «Запасной выход». И хоть бы одна зараза написала «запасной вход».
(С) Дмитрий Емец. Мефодий Буслаев. Месть валькирий


Начиная писать свой Биксодж, я не задавался целью утереть нос лидеру go-роутеров *Httprouter* в скорости обработки запроса. То, что мой код оказался быстрым, это скорее приятный бонус. На мой взгляд, у приложения, использующего роутер, этот самый роутер вряд-ли будет узким горлышком. Но если задаваться целью написать действительно быстрое приложение, то… другое дело. Скорей всего это будет маленькое приложение, сервис или ещё что-то в таком духе. Для больших и сложных приложений скорость перестаёт быть единственным и самым важным критерием.

А как же работа?

Работу я не нашёл, поскольку ещё не искал. Очень бы хотелось в комментариях прочитать про реальные ситуации рынка Go-программистов, а то меня тут разобрали сомнения, может сразу покупать новый учебник по языку ХХХ :)
github.com/claygod/Bxog
github.com/claygod/BxogTest
Поделиться с друзьями
-->

Комментарии (26)


  1. impwx
    20.05.2016 14:26
    +4

    1. claygod
      20.05.2016 14:33

      Упс, это мой так сказать внутренний юмор(напоминалочка)
      Пожалуй, спрячу от неокрепших умов )) Спс


      1. Xazzzi
        21.05.2016 19:21

        Кто ищет, тот всегда найдет.


  1. rumkin
    20.05.2016 14:29
    +1

    Не "Биксоджей", а "Биксодж".


    1. claygod
      20.05.2016 14:37

      Поскольку учил я французский, то за консультацией обращался к переводчику Гугла,
      он в конце говорит «джей», ну а с корпорацией добра спорить…


      1. deniskreshikhin
        20.05.2016 15:04
        +1

        В гугл би-экс-оу-джи )) Джей в английском это J.


        1. claygod
          20.05.2016 15:10

          Когда нажимаю кнопку Прослушать, мне слышится в конце джей, а вам?

          Странно, но мне нравятся все вариации чтения названия, уже предложенные )
          Осталось спросить, а что думают по этому поводу носители языка


          1. deniskreshikhin
            20.05.2016 15:25
            +1

            Это потому что там джи с долгим и [i:]. Да, русскоязычными он воспринимает как «ий»/«ей», как пример, нидерландское koffie с долгим [i:] превратился в «кофей» (еще есть форма «кофий»). У вас видимо так же получилось)))


            1. claygod
              20.05.2016 15:29

              deniskreshikhin, а на ваш взгляд, предложенный rumkin вариант Биксодж может быть правильным?


              1. deniskreshikhin
                20.05.2016 15:39
                +1

                Я думаю, даже англичане на это не ответят, т.к. «x» не может в английском следовать за согласным.
                Если читать по буквам, то «би-экс-оу-джи». Если читать как слово, то будет что-то вроде «бксог» или «бзог».


                1. claygod
                  20.05.2016 15:51
                  +1

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


                  1. S_Nil
                    20.05.2016 20:38
                    +5

                    Вспомнился анекдот :)
                    Русский, французский и китайский лингвисты решили написать имена друг друга, каждый на своём языке.

                    — Моя фамилия Ге, — сказал француз китайцу.
                    — В китайском языке два иероглифа Ге, но, к сожалению, ни один из них не подходит для фамилии.
                    — Почему?
                    — Потому что один имеет значение «колесо», а другой передает звук, с которым лопается мочевой пузырь осла.
                    — А что плохого в колесе?
                    — Мужское имя не может быть круглым. Для твоего имени мы возьмем иероглиф Шэ, означающий «клавиатура», «корнеплод», «страница», а также прилагательное «бесснежный» и дополним его иероглифом Нгу, означающим мужской род. В конце я пишу иероглиф Мо — «девственный».
                    — Но это, мягко говоря, не совсем…
                    — Никто не будет считать тебя девственником, просто без иероглифа Мо иероглифы Ше-Нгу означают «сбривающий мамины усы».

                    — Хорошо, теперь я напишу твое имя.
                    — Моя фамилия Го.
                    — Отлично, я начну твою фамилию с буквы G.
                    — Что означает буква G?
                    — У нас, европейцев, сами по себе буквы ничего не значат, но чтобы проявить к тебе уважение, я поставлю перед G букву H — во французском она все равно не читается.
                    — Отлично! Дальше O?
                    — Нет, чтобы показать, что G — произносится как Г, а не как Х, надо после G поставить букву U, а также H — чтобы показать, что U не читается сама по себе, а только показывает, как правильно читать G, и буквы EY, показывающие, что слово не длинное и скоро закончится.
                    — Hguhey… дальше O?
                    — Нет, О во французском произносится как А или Ё, в зависимости от стоящих по соседству букв, ударения и времени года. Твое чистое О записывается как AUGHT, но слово не может кончаться на T, поэтому я добавлю нечитаемое окончание NGER. Вуаля!

                    Русский лингвист поставил бокал на стол, взял листочек и написал «Го» и «Ге».
                    — И всё?
                    — Да.

                    Француз с китайцем почесали в затылке.
                    — Хорошо, а какая у тебя фамилия?
                    — Щекочихин-Крестовоздвиженский.
                    — А давайте просто выпьем? — первым нашёлся китаец.

                    Русский кивнул и француз с облегчением поднял тост за шипящие дифтонги.


  1. rumkin
    20.05.2016 14:30

    deleted


  1. iga2iga
    20.05.2016 15:00
    +1

    Бииксоуджи, если быть точным. У гугла какой-то свой, видимо, «английский».


    1. claygod
      20.05.2016 15:13

      Если не будет новых версий, поправлю в статье на Бииксоуджи.
      Название мне стало напоминать не безызвестный фильм Джуманджи.


      1. feudorsam
        20.05.2016 18:22

        Не-е. deniskreshikhin правильно сказал. b — би, x — экс, о — оу, g — джи


    1. PavelMSTU
      21.05.2016 09:40

      Может быть этот «какой-то свой английский» делала команда из Гарварда или MIT'а (3-е и 6-е места)? ;)


  1. lain8dono
    20.05.2016 15:31
    +3

    When in Go, do as Gophers do.


    Не следует тесты в другой репозиторий отправлять. Они мешать не будут. Достаточно, чтоб имя у них подходило под маску *_test.go. По этой теме можно ещё документацию пакета go/build почитать.


    Кроме того не принято использовать CAPS_CASE для констант. Effective Go #mixed-caps.


    Тип Node не используется нигде, кроме внутренностей. Можно его скрыть из видимости. Достаточно написать node. Аналогично с Section, Index и внутренними константами. Кстати golint вам об этом укажет.


    Ещё по можно почитать CodeReviewComments.


    Мааленький момент. Не документируйте файлы. Документируйте сущности. Неплохо было бы добавить либеральную лицензию и заодно убрать из файликов упоминание о себе любимом. Ну или по возможности сократить в одну строчку и написать её перед package main. Не забудьте пустую строку после такого комментария, иначе оно уже как документация будет.


    По мимо прочего неплохо иметь ссылку на документацию прямо сверху README. Вот она: https://godoc.org/github.com/claygod/Bxog


    1. claygod
      20.05.2016 16:08

      Не следует тесты в другой репозиторий отправлять. Они мешать не будут. Достаточно, чтоб имя у них подходило под маску *_test.go. По этой теме можно ещё документацию пакета go/build почитать.

      Знаю, это я из своих соображений.

      Кроме того не принято использовать CAPS_CASE для констант. Effective Go #mixed-caps.

      Как-то не обращал внимания. В принципе, поправить можно, хотя привычно большими буквами.

      Тип Node не используется нигде, кроме внутренностей. Можно его скрыть из видимости. Достаточно написать node. Аналогично с Section, Index и внутренними константами. Кстати golint вам об этом укажет.

      Кстати да, собирался убрать из области видимости, но хотел оставить в названиях большие буквы.
      Впишется ли в норму вариант вместо Node -> bNode?

      Мааленький момент. Не документируйте файлы. Документируйте сущности. Неплохо было бы добавить либеральную лицензию и заодно убрать из файликов упоминание о себе любимом. Ну или по возможности сократить в одну строчку и написать её перед package main. Не забудьте пустую строку после такого комментария, иначе оно уже как документация будет.

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

      По мимо прочего неплохо иметь ссылку на документацию прямо сверху README. Вот она: https://godoc.org/github.com/claygod/Bxog

      Добавил.

      lain8dono, спасибо за комментарий, побольше бы таких!


      1. lain8dono
        20.05.2016 17:06

        Впишется ли в норму вариант вместо Node -> bNode?

        Не особо, но лучше. Это будет выглядеть странновато для читающих код, хотя чуть лучше для читающих только документацию. Кстати node не на столько уж большая структура для того, чтоб выделять её в отдельный файл. Лично я оставил бы её в файле index.go.


        Кстати нижнего подчёркивание в именах вообще следует избегать.


        Линтёр ругается вот так:

        `


        $ golint -min_confidence 0
        config.go:3:1: should have a package comment, unless it's in another file for this package
        config.go:8:6: don't use underscores in Go names; type type_hash should be typeHash
        config.go:12:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:13:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:20:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:24:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:27:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:30:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:33:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:36:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:39:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:44:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:45:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:46:2: don't use ALL_CAPS in Go names; use CamelCase
        config.go:47:2: don't use ALL_CAPS in Go names; use CamelCase
        index.go:1:1: should have a package comment, unless it's in another file for this package
        index.go:12:6: exported type Index should have comment or be unexported
        index.go:26:2: don't use underscores in Go names; var c_hashes should be cHashes
        index.go:28:6: don't use underscores in Go names; var c_node should be cNode
        index.go:45:10: if block ends with a return statement, so drop this else and outdent its block
        index.go:73:3: don't use underscores in Go names; var c_node should be cNode
        index.go:80:3: don't use underscores in Go names; var c_hash should be cHash
        index.go:102:5: don't use underscores in Go names; var new_node should be newNode
        index.go:123:57: don't use underscores in Go names; method parameter c_hashes should be cHashes
        node.go:3:1: should have a package comment, unless it's in another file for this package
        node.go:7:1: comment on exported type Node should be of the form "Node ..." (with optional leading article)
        node.go:14:2: don't use underscores in Go names; var new_node should be newNode
        route.go:1:1: should have a package comment, unless it's in another file for this package
        route.go:13:6: exported type Route should have comment or be unexported
        route.go:40:9: if block ends with a return statement, so drop this else and outdent its block
        route.go:46:1: exported method Route.Method should have comment or be unexported
        route.go:51:1: exported method Route.Id should have comment or be unexported
        route.go:51:17: method Id should be ID
        route.go:56:17: method parseUrl should be parseURL
        route.go:57:6: don't use underscores in Go names; var array_sec should be arraySec
        router.go:3:1: should have a package comment, unless it's in another file for this package
        router.go:14:1: comment on exported type Router should be of the form "Router ..." (with optional leading article)
        router.go:21:1: comment on exported function New should be of the form "New ..."
        router.go:26:1: comment on exported method Router.Add should be of the form "Add ..."
        router.go:31:9: if block ends with a return statement, so drop this else and outdent its block
        router.go:36:1: comment on exported method Router.Start should be of the form "Start ..."
        router.go:52:1: comment on exported method Router.Params should be of the form "Params ..."
        router.go:55:5: don't use underscores in Go names; var c_route should be cRoute
        router.go:66:1: comment on exported method Router.Create should be of the form "Create ..."
        router.go:81:1: comment on exported method Router.Test should be of the form "Test ..."
        section.go:3:1: should have a package comment, unless it's in another file for this package
        section.go:7:1: comment on exported type Section should be of the form "Section ..." (with optional leading article)
        section.go:10:2: don't use underscores in Go names; struct field type_sec should be typeSec
        section.go:13:29: don't use underscores in Go names; func parameter type_s should be typeS
        server.go:3:1: should have a package comment, unless it's in another file for this package
        server.go:16:9: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
        

        `


        1. claygod
          20.05.2016 17:31
          +1

          Кстати, а у вас есть бенчмарк на костыль с хешированием? На сколько это лучше/хуже чем map[string]T?

          Прямого нет, делал две версии поиска и сравнивал по общему бенчмарку. Но однозначно могу сказать, что сгенерировать хэш дешевле. Если бы вернуть старый алгоритм со строками, то думаю, сотня ns/op тут же набежала бы. И ещё я заметил, что с строками результат какой-то менее стабильный (больший разброс), хотя возможно это сугубо субъективно.


          1. lain8dono
            20.05.2016 21:55
            +1

            Но однозначно могу сказать, что сгенерировать хэш дешевле.

            Однозначно об этом может сказать ТОЛЬКО правильно написанный бенчмарк. Более того. Вы заменяете стандартную функциональность языка собственным костылём. Следовательно далеко не лишним будет описание вашего алгоритма хеширования и объяснения, почему так лучше/быстрее/сильнее/выше и т.д. Желательно ещё и минусы (которые в любом случае есть) такого подхода обозначить.


            Споры без бенчмарков о производительности можно приравнять к разговорам о политике.


            Если очень хочется посоревноваться, то можно начать с https://github.com/gin-gonic/go-http-routing-benchmark


            Кстати. Ваши тесты не заработают практически везде, кроме винды
            $ go test -v            
            # github.com/claygod/BxogTest
            bxog_test.go:22:2: cannot find package "github.com/claygod/bxog" in any of:
                /usr/lib/go/src/github.com/claygod/bxog (from $GOROOT)
                /home/lain/gocode/src/github.com/claygod/bxog (from $GOPATH)
            FAIL    github.com/claygod/BxogTest [setup failed]
            


            1. claygod
              21.05.2016 10:19
              +1

              Ваши тесты не заработают практически везде, кроме винды

              Не соображу сразу… из-за того, что bxog в импортах написан с маленькой буквы? Плз, подскажите.

              Если очень хочется посоревноваться, то...

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

              Следовательно далеко не лишним будет описание вашего алгоритма хеширования и объяснения, почему так лучше/быстрее/сильнее/выше и т.д. Желательно ещё и минусы (которые в любом случае есть) такого подхода обозначить.

              Согласен, ключевой момент стоит осветить.


    1. claygod
      23.05.2016 09:31

      Тип Node не используется нигде, кроме внутренностей. Можно его скрыть из видимости. Достаточно написать node. Аналогично с Section, Index и внутренними константами. Кстати golint вам об этом укажет.


      Поправил, в https://godoc.org/github.com/claygod/Bxog теперь только публичные функции роутера для API


  1. knagaev
    23.05.2016 14:44
    +1

    На Гитхабе в
    Settings
    Necessary changes in the configuration of the multiplexer can be made in the configuration file config.go
    ссылка с config.go ведёт в никуда.


    1. claygod
      23.05.2016 18:39

      Спасибо, пофиксил