[Python, Программирование, Анализ и проектирование систем, Интерфейсы, Go] Порт GUI фреймворка с Python на Go. Анализ граблей и плюшек

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
26-Фев-2021 12:32


С Python мне пришлось работать от безнадеги - ML, нейросетки, скриптинг, то-сё сподручнее было именно на нем. Но время идет и тревога за скорость своего кода толкает к чему то быстрому и более надежному.  Задача портировать GUI framework наболела, потому что мой универсальный Unigui работал только из Python и универсальным был только в теории. В нем был наработан предельно лаконичный API, который должен был быть сохранен и в Go варианте.  Кроме того масса автоматизма по  генерации нужных данных портированию не подлежала, т.к. в Go отсутствует управление порядком компиляции, препроцессор,метапрограммирование, что гарантировало непростой спартанский трип.Первой сложностью, в которую я наступил, была невозможность напрямую присваивать promouted(вложенные) поля в инициализаторе структур и только в нем. Если структура имеет безымянную вложенную структуру, то к ее полям можно обращаться из корня внешней везде, кроме инициализатора. Из-за чего, в том числе, вся затея с вложенными полями как с заменой иерархии стала и сомнительной, и громоздкой в использовании. Требовать от юзера либы писать длинные  вложенные с ненужными типами инициализаторы было бы верхом неприличия.  Все GUI структуры стали абсолютно плоские, независимые, хотя в Python есть четкая иерархия.Словоблудие, которые Go требовал при сборке объектов, все равно оставалось. Пользователю библиотеки нужен краткий понятный вызов, а тут я должен заставить его помнить поля объекта и использовать в инициализаторе и каким-то образом указать, что некоторые должны быть обязательно заполнены, а дефолтные параметры низзя,они, как оказалось, “следствие плохого дизайна API”. Золотые слова, как обычно, с реальностью не коррелирующие. Было решено спрятать это с глаз и дать юзеру набор хэлперов с теми же именами, что должны быть у типов, которые будут делать всю нудную работу и возвращать сразу указатель. Что пользователю легко забыть  хэлпер сделает сам. Типы объектов стали выглядеть как Type_ a хелпер Type(…) возвращает *Type_. По сути, это конструкторы из ООП, чтобы скрыть неприглядные моему и юзера либы взору кишки Go кода.Сериализация Go в Json не осталась в стороне и взбодрила порцией эзотерики в своих деталях. nil работает как пустой массив в вызовах функций слайсов (массивы переменной длины), однако при сериализации поля слайса с nil он продолжает быть nil a не как во всех других языках/библиотеках [ ] . То, что тип переменной слайс - по фигу. Оk, Google, возьмем стороннюю либу с фиксом на это дело или будем в хелперах проверять, если массив == nil, то надо ему написать = make(0, []Any). Если поле структуры имеет неинициализированный указатель на функцию, то напрямую он == nil, а если запросить его значение через reflect то он != nil. Однако если дописать бессмысленную на первый взгляд reflect.ValueOf(ptr).IsNil() то, о чудо, это true! Гениально, чо..Добить меня они решили отсутствием стандартной функции hash. Так мне тогда показалось. Это ж надо было умудриться. Проверил на всякий случай список арифметических операторов. Вроде все есть. Выдохнул и стал пробираться дальше.Почему можно выводить и не писать тип для простой переменной можно, но нельзя для массива или мапы?? Ведь итоговый тип либо равен типу первой переменной, если он совпадает с остальными в списке, либо Any - interface{}. Всё! А потому явно писать тип для мапов и слайсов,  когда он 100% очевиден - это проявление внимания к работе компилятора. “Вам мелочь, а ему приятно!” Про ненормальное определение видимости переменных и функций через регистр первой буквы. Наверное, это не новость, однако же и ломка сознания (известные мне языки такую дичь не используют) и путаница, где тип, а где объект. Если кажется что к этому можно привыкнуть и перетерпеть, то дичь будет лезть везде, где пролезет. Вот хотим мы сделать сериализацию готового протокола, а имена в нижнем регистре использовать не можем (доступа не будет). Любезный Google предлагает нам костыль с блестками в виде добавок к описанию поля типа MyField int json:"myfield" и вроде бы ничего, с JSON мы выпутываемся. Подумаешь - пробежаться по сотне-другой полей и дописать эту фуфу. А если сериализация в другой протокол? Тогда, горемычные, - ваши проблемы, они и так вон чего тебе аж, а вам все мало. Пиндюрь к каждой структуре свою функцию кодирования и радуйся что ээ.. да просто радуйся! Тот же гугловый Dart имеет симпатичную декларацию видимости через _ впереди для ее ограничения. К слову сказать, ВСЕ печальки Go в Dart-е отсутствуют, и наоборот. Т. е.  создается ощущение, что кривозубые решения в дизайне языков в Google решили между ними поделить, и ни один такой “прикол” не вошел одновременно в оба языка. Кто это, интересно, у них это раздает, и следит, чтоб всем поровну?Отсутствием на данный момент дженериков, функторов map/filter/.. , коротких лямбд и даже таких элементарных операций с массивами как RemoveAtIndex, возмущались и до меня, но с добавкой дженериков в 1.17 часть этого уйдет, но я готов поставить ящик мороженого, что в них докинут новой эпидерсии, чтоб не сильно радовались.Зачем вам интерполяции строк? Забейте! Вместо этого предлагается использовать разлапистый fmt.Sprintf. Что за необходимость писать допотопный С-код в современном языке - тайна великая, а их объяснение, что это сложно компилятору - “муть и компот”.Но есть же  и приятные моменты.
  • И главный - это скорость. Ощущение, когда пересядешь с допотопного ноута на  фаршированный десктоп. Как то сразу хочется понять и простить, остаться,  задумываешься как ML-ить на Go… 
  • Конкурентность/параллелизм. Почувствовав разницу, понимаешь, что использование для нагруженных задач Python-a вместо Go - нехорошо ни разу. Модель гоуроутин - ясная, простая, минимум усилий, максимум выхлопа. Python здесь сливает как бомж-алкоголик директору винзавода.
  • Сборка/компиляция - здесь в плюс Go. Импорт либ из github (жирный лайк), мгновенная инкрементная компиляция это не кот накашлял. Правда, последнее уже было в Visual C++ ~20 лет назад, Edit & Continue называлось. Оно, Edit & Continue для Go в моем VS Code не работает, хотя при каждом редактировании при запущенной проге пугает, что изменения якобы внесены. Ни-фи-га. Ну то такое ..
  • Объем кода. Примерно одинаково. Что весьма хорошо для Go. Плохо, что добиться этого сразу нельзя. Медитировать, переписывать, хэлперы, алиасы - тогда можно. -Дизайн кода. Довольно просто подсчитать, что если бы Go поддерживал элементарное наследование, то кода в моей либе стало бы на 20% меньше. И работала бы она минимум вдвое быстрее за счет исключения 70% reflect кода. И написал бы вдвое быстрее. Так что лично мне понятно, что вся эта типо инкапсулирующая модель создает больше проблем чем пользы. Причем существенно. 
  • Сравнение кода. Для создания вот этого экрана в браузере (сервера по умолчанию вешаются на 8000 порт) код на Python и Go.

Go
package main
import . "github.com/Claus1/unigui-go"
func screenTest(user* User)* Screen_{
  table := Table("Videos",0, nil, []string{"Video", "Duration",  "Links", "Mine"},
  SeqSeq(Seq("opt_sync1_3_0.mp4", "30 seconds",  "@Refer to signal1", true),
    Seq("opt_sync1_3_0.mp4", "37 seconds",  "@Refer to signal8", false)))
  cleanButton := Button("Clean table", nil, "")
  selector := Select("Select", "All", nil, []string{"All","Based","Group"})
  block := Block("X Block", Seq(cleanButton, selector), table)
  block.Icon = "api"
  return Screen(block)
}
func main(){
  //register screens
  Register(screenTest, "Main", 0, "insights")
  Start()
}
Python
from unigui import *
name = "Main" #name of screen to show
icon = 'blur_linear' #MD icon of screen to show
order = 0 #order in the program menu
table = Table('Videos', 0, headers = ['Video', 'Duration',  'Links', 'Mine'],rows = [
    ['opt_sync1_3_0.mp4', '30 seconds',  '@Refer to signal1', True],
    ['opt_sync1_3_0.mp4', '37 seconds',  '@Refer to signal8', False]
])
block = Block('X Block',
    [
        Button('Clean table'),
        Select('Select', value='All', options=['All','Based','Group'])
    ], table, icon = 'api')
blocks = [block] #what to show on the screen
start('Test app')
Буду ли использовать Go дальше? Куда ж я денусь с подводной лодки.. и  сильно хочу, чтоб Crystal, Nim, и прочие простые, развитые языки ворвались в продакшен и дали Go пендаля. Пока, к сожалению, альтернативы ему в нише легкой продакшен разработки производительного ПО не наблюдаю. Peace!Ссылки для любознательных:https://github.com/Claus1/unigui-go Go https://github.com/Claus1/unigui      Python 
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_python, #_programmirovanie (Программирование), #_analiz_i_proektirovanie_sistem (Анализ и проектирование систем), #_interfejsy (Интерфейсы), #_go, #_portirovanie (портирование), #_gui, #_frontend, #_backend, #_razrabotka (разработка), #_python, #_programmirovanie (
Программирование
)
, #_analiz_i_proektirovanie_sistem (
Анализ и проектирование систем
)
, #_interfejsy (
Интерфейсы
)
, #_go
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 08:34
Часовой пояс: UTC + 5