В данном случае используется довольно простой алгоритм Round-Robin.
Начнем с базового объекта server, который содержит 3 атрибута, связанных с сервером
• Address()
• IsAlive()
• Функция Serve() для работы с запросами
type Server interface {
Address() string
IsAlive() bool
Serve(rw http.ResponseWriter, req *http.Request)
}
В дальнейшем используется второй тип объекта – simpleServer.
type simpleServer struct {
addr string
proxy *httputil.ReverseProxy
}
После определения методов, используемых в указанных объектах, мы создаем loadbalancer вместе с функцией getNextAvailableServer().
func NewLoadBalancer(port string, servers []Server) *LoadBalancer {
return &LoadBalancer{
port: port,
roundRobinCount: 0,
servers: servers,
}
}
func (lb *LoadBalancer) getNextAvailableServer() Server {
server := lb.servers[lb.roundRobinCount%len(lb.servers)]
for !server.IsAlive() {
lb.roundRobinCount++
server = lb.servers[lb.roundRobinCount%len(lb.servers)]
}
lb.roundRobinCount++
return server
}
Вызываем main()
func main() {
servers := []Server{
newSimpleServer("https://snapcraft.io"),
newSimpleServer("https://github.com/sambhavsaxena"),
newSimpleServer("http://localhost:3001"),
}
lb := NewLoadBalancer("3000", servers)
handleRedirect := func(rw http.ResponseWriter, req *http.Request) {
lb.serveProxy(rw, req)
}
http.HandleFunc("/", handleRedirect)
fmt.Printf("distributing requests fired at 'localhost:%s'\n", lb.port)
http.ListenAndServe(":"+lb.port, nil)
}
▪Статья
▪Полный код
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Изменение порядка следования элементов связного списка
Сложность: Средняя
Условие задачи : дан связный список:
L0 → L1 → … → Ln - 1 → Ln.
Надо переопределить порядок следования элементов на следующий:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
Пример:
Ввод: head = [1,2,3,4]
Вывод: [1,4,2,3]
Ввод: [1,2,3,4,5]
Вывод: [1,5,2,4,3]
Решение задачи
Пишите свое решение в комментариях👇
@golang_interview
Сложность: Средняя
Условие задачи : дан связный список:
L0 → L1 → … → Ln - 1 → Ln.
Надо переопределить порядок следования элементов на следующий:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
Пример:
Ввод: head = [1,2,3,4]
Вывод: [1,4,2,3]
Ввод: [1,2,3,4,5]
Вывод: [1,5,2,4,3]
Решение задачи
Пишите свое решение в комментариях👇
@golang_interview
Лучший способ получать свежие обновлении и следить за трендами в разработке.
Python: t.me/pythonl
C#: t.me/csharp_ci
C/C++/ t.me/cpluspluc
Машинное обучение: t.me/ai_machinelearning_big_data
Data Science: t.me/data_analysis_ml
Devops: t.me/devOPSitsec
Go: t.me/Golang_google
Базы данных: t.me/sqlhub
Rust: t.me/rust_code
Javascript: t.me/javascriptv
React: t.me/react_tg
PHP: t.me/phpshka
Android: t.me/android_its
Мобильная разработка: t.me/mobdevelop
Linux: t.me/+A8jY79rcyKJlYWY6
Big Data: t.me/bigdatai
Хакинг: t.me/linuxkalii
Java: t.me/javatg
Папка Go разработчика: t.me/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: t.me/addlist/eEPya-HF6mkxMGIy
🇬🇧Английский: t.me/english_forprogrammers
Please open Telegram to view this post
VIEW IN TELEGRAM
Стратегия (. Strategy) — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путём определения соответствующего класса. Шаблон Стратегия (. Strategy) позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.
Реализация шаблона представлена на кратинке.
В примере у объекта toy есть DialogueReciter, который является интерфейсом, и это важно, поскольку мы хотим, чтобы поведение объекта-игрушки можно было изменять во время выполнения программы. Если бы это был не интерфейс, а конкретный тип, то мы могли бы присвоить объекту-игрушке только поведение этого конкретного типа.
Поведение для объекта toy определено в интерфейсе, а фактическая реализация поведения, например, Recite, выполняется отдельно различными конкретными типами, например, SpiderMan, SuperMan и BatMan.
Если бы поведение toy было закодировано в конкретном типе, то мы были бы заблокированы на использование только этого конкретного поведения.
Поэтому можно сказать, что "программируй под интерфейс, а не под реализацию", и это важный принцип проектирования.
"Паттерн стратегии" определяет семейство алгоритмов,
инкапсулирует каждый из них и делает их взаимозаменяемыми.
Стратегия позволяет алгоритму изменяться независимо от
клиентов, которые его используют".
Пишите свой пример реализации шаблона в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Когда вы начинаете новый проект на Go, вы можете начать с клонирования существующего проекта. Таким образом, вы можете начать с уже работающего проекта, внося в него постепенные изменения, а не начинать с нуля.
Gonew - экспериментальный инструмент для создания новых проектов на языке Go на основе предопределенных шаблонов. Любой программист может написать шаблоны, которые упаковываются и распространяются как модули.
Начните с установки gonew с помощью go install:
$ go install golang.org/x/tools/cmd/gonew@latest
Чтобы скопировать существующий шаблон, запустите gonew в родительском каталоге нового проекта с двумя аргументами: первый - путь к шаблону, который необходимо скопировать, второй - имя модуля создаваемого проекта. Например:
$ gonew golang.org/x/example/helloserver example.com/myserver
$ cd ./myserver
А затем вы можете читать и редактировать файлы в ./myserver для настройки.
Для начала мы написали два шаблона:
hello: Инструмент командной строки, печатающий приветствие, с флагами настройки.
helloserver: HTTP-сервер, передающий приветствия.
https://go.dev/blog/gonew
Еще примеры: https://github.com/GoogleCloudPlatform/go-templates@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Мьютекс гораздо более комплексная структура по сравнению с atomic, чем может показаться на первый взгляд. Прежде всего у нас есть два вида мютексов:
sync.Mutex
и sync.RWMutex
. У каждого из них есть методы Lock
и Unlock
, у RWMutex
есть дополнительно метод RLock
(блокирование для чтения). В обоих типах методы Lock
довольно долгие по сравнению с атомиками.У
Mutex
код метода Lock
включает два вида блокировки. Первый вариант - это когда удается захватить не заблокированный мьютекс, второй вариант довольно долгий и он запускается если мьютекс заблокирован:// Lock locks m.
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available.
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if race.Enabled {
race.Acquire(unsafe.Pointer(m))
}
return
}
// Slow path (outlined so that the fast path can be inlined)
m.lockSlow()
}
Первый вариант довольно быстрый и включает в себя одну
atomic
операцию. Второй вариант включает довольно много кода и здесь подробно разбираться не будет: там также используются атомики в процессе блокировки, но очевидно, что он исполняется еще дольше первого варианта (Fast path).У
RWMutex
код метода Lock
включает в себя вызов метода Lock
структуры Mutex
:// Lock locks rw for writing.
// If the lock is already locked for reading or writing,
// Lock blocks until the lock is available.
func (rw *RWMutex) Lock() {
if race.Enabled {
_ = rw.w.state
race.Disable()
}
// First, resolve competition with other writers.
rw.w.Lock()
// Здесь пропущена часть кода ...
}
}
Да и сама структура
RWMutex
включает в себя структуру Mutex
как одно из полей:
type RWMutex struct {
w Mutex // held if there are pending writers
// Здесь пропущена часть кода ...
}
Метод
RLock
у RWMutex
гораздо быстрее и содержит меньше кода, но тем не менее не быстрее атомика, который там задействован:
func (rw *RWMutex) RLock() {
// Здесь пропущена часть кода ...
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// A writer is pending, wait for it.
runtime_SemacquireMutex(&rw.readerSem, false, 0)
}
//
📌Вопрос что производительнее атомики или мьютексы?
Напишите свой ответ в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
600 сайтов для поиска вакансий по всему миру
https://hellonewjob.org/tech-vacacny-sources
@golang_interview
https://hellonewjob.org/tech-vacacny-sources
@golang_interview
hellonewjob.org
Список ресурсов, которые помогут с поиском вакансий в IT/Tech и не только
список из 600+ ресурсов, которые помогут вам с поиском вакансий в IT/Tech и не только. Список не исчерпывающий
http.ResponseController:
•Позволяет переопределять ваши общесерверные таймауты/дедлайны чтения и записи новыми для каждого отдельного запроса.
•Шаблон использования интерфейсов http.Flusher и http.Hijacker стал более понятным и менее сложным. Нам больше не нужны никакие утверждения типов!
•Он делает проще и безопаснее создание и использование пользовательских реализаций http.ResponseWriter.
Таймауты для отдельных запросов
http.Server Go имеет настройки ReadTimeout и WriteTimeout, которые вы можете использовать для автоматического закрытия HTTP-соединения, если время, затраченное на чтение запроса или запись ответа, превышает какое-либо фиксированное значение. Эти настройки являются общесерверными и применяются ко всем запросам, независимо от обработчика или URL.
С появлением http.ResponseController можно использовать методы SetReadDeadline() и SetWriteDeadline(), чтобы ослабить или, наоборот, ужесточить эти настройки для каждого конкретного запроса в зависимости от ваших потребностей. Например:
func exampleHandler(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)
// Установим таймаут записи в 5 секунд.
err := rc.SetWriteDeadline(time.Now().Add(5 * time.Second))
if err != nil {
// Обработка ошибки
}
// Делаем здесь что-нибудь...
// Записываем ответ как обычно
w.Write([]byte("Done!"))
}
Это особенно полезно для приложений, содержащих небольшое количество обработчиков, которым требуются более длительные таймауты, чем всем остальным, для таких вещей, как обработка загрузки файла или выполнение длительной операции.
Несколько деталей, о которых стоит упомянуть:
Если вы установите очень короткий общесерверный таймаут, и этот таймаут будет достигнут до того, как вы вызовете SetWriteDeadline() или SetReadDeadline(), то они не возымеют никакого эффекта. Общесерверный таймаут в этом случае побеждает.
Если базовый http.ResponseWriter не поддерживает установку таймаутов для отдельных запросов, то вызов SetWriteDeadline() или SetReadDeadline() вернет ошибку http.ErrNotSupported.
Теперь можено отменять общесерверный таймаут для отдельных запросов, передав обнуленную структур time.Time в SetWriteDeadlin() или SetReadDeadline(). Например:
rc := http.NewResponseController(w)
err := rc.SetWriteDeadline(time.Time{})
if err != nil {
// Обработка ошибки
}
Интерфейсы Flusher и Hijacker
Тип http.ResponseController также делает более удобным использование «опциональных» интерфейсов http.Flusher и http.Hijacker. Например, до Go 1.20, чтобы отправить данные ответа клиенту, вы могли использовать кода следующего вида:
func exampleHandler(w http.ResponseWriter, r *http.Request) {
f, ok := w.(http.Flusher)
if !ok {
// Обработка ошибки
}
for i := 0; i < 5; i++ {
fmt.Fprintf(w, "Write %d\n", i)
f.Flush()
time.Sleep(time.Second)
}
}
Теперь можно сделать это так:
func exampleHandler(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)
for i := 0; i < 5; i++ {
fmt.Fprintf(w, "Write %d\n", i)
err := rc.Flush()
if err != nil {
// Обработка ошибки
}
time.Sleep(time.Second)
}
}
Шаб
лонный код перехвата (hijacking) соединения аналогичен:
func (app *application) home(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)
conn, bufrw, err := rc.Hijack()
if err != nil {
// Обработка ошибки
}
defer conn.Close()
// Делаем здесь что-нибудь...
}
Опять же, если ваш базовый
http.ResponseWriter не поддерживает flush или перехват соединения, то вызов Flush() или Hijack() в http.ResponseController также вернет ошибку http.ErrNotSupported.
Теперь также проще и безопаснее создавать и использовать пользовательские реализации http.ResponseWriter, которые поддерживают flush и перехват соединения.
Приведите пример с кодом реализации своей http.ResponseWriter в комментариях 👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Работу кэша можно оценивать при помощи множества метрик разной степени полезности. Перечислим те, которые которые считаю базовыми и наиболее полезными.
▪Объем памяти, выделенной под кэш. Это базовый показатель, по которому можно судить, сколько используется ресурсов
▪RPS чтения/записи – количество операций чтения/записи за единицу времени. В обычной ситуации количество операций чтения должно быть в разы больше количества операций записи. Обратное соотношение свидетельствует о проблемах в работе кэша
▪Количество элементов в кэше. Его полезно знать в дополнение к объему памяти, чтобы обнаруживать большие записи
▪Hit rate – процент извлечения данных из кэша. Чем он ближе к 100%, тем лучше. Этот параметр буквально определяет то, насколько наш кэш полезен и эффективен
▪Expired rate – процент удаления записей по истечении TTL. Этот показатель помогает обнаружить проблемы с производительностью, вызванные большим количеством записей с одновременно истекшим TTL
▪Eviction rate – процент вытеснения записей из кэша при достижении лимита используемой памяти. Важный показатель при выборе стратегий вытеснения, о которых мы поговорим чуть позже
Что можно кэшировать?
Строго говоря, кэшировать можно что угодно, но не всегда это целесообразно. Все сильно зависит от данных и паттерна их использования.
Все данные можно условно разделить на 3 группы по частоте изменений:
▪Меняются часто. Такие данные изменяются в течение секунд или нескольких минут. Их кэширование чаще всего бессмысленно, хотя иногда может и пригодится.
Пример: ошибки (кэширование ошибок может быть настолько важным, что мы посвятили ему целую главу ближе к концу статьи)
▪Меняются нечасто. Такие данные изменяются в течение минут, часов, дней. Именно в этом случае вы чаще всего задаетесь вопросом “Стоит ли мне кэшировать это?”
Примеры: списки товаров на сайте, описания товаров
▪Меняются крайне редко или не меняются никогда. Такие данные меняются в течение недель, месяцев и лет. В этом случае данные можно спокойно кэшировать. НО! Ни в коем случае нельзя усыплять бдительность верой в то, что какие-либо данные никогда не изменятся. Рано или поздно они изменятся, поэтому всегда выставляйте всем данным разумный TTL. ВСЕГДА!
Напишите какие стратегии работы с кэшем вы знаете в комментариях 👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
✔ Как управлять сборщиком мусора в GO? Приведите пример с кодом.
Существует параметр, который позволяет управлять сборщиком мусора в Go - это переменная окружения GOGC или ее функциональный аналог SetGCPercent из пакета runtime/debug.
Параметр GOGC определяет процент новой необработанной памяти кучи от живой памяти, при достижении которого будет запущена сборка мусора. Значение GOGC по умолчанию равно 100, что означает, что сборка мусора будет запущена, когда объем новой памяти достигнет 100% от объема живой памяти
Рассмотрим пример программы и отследим изменение размера кучи с помощью инструмента go tool trace. Для запуска программы используем версию Go 1.20.1.
В данном примере, функция performMemoryIntensiveTask использует большое количество памяти размещаемой в куче. Данная функция запускает обработчик с размером очереди NumWorker и количество задач равное NumTasks.
Для трассировки работы программы результат записывается в файл trace.out:
Используя инструмент go tool trace, мы можем наблюдать за изменениями размера кучи и анализировать поведение сборщика мусора в вашей программе.
Hidden text
Обратите внимание, что точные детали и возможности инструмента go tool trace могут варьироваться в разных версиях Go, поэтому рекомендуется обратиться к официальной документации для получения более подробной информации о его использовании в вашей конкретной версии Go.
▪Статья
@golang_interview
Существует параметр, который позволяет управлять сборщиком мусора в Go - это переменная окружения GOGC или ее функциональный аналог SetGCPercent из пакета runtime/debug.
Параметр GOGC определяет процент новой необработанной памяти кучи от живой памяти, при достижении которого будет запущена сборка мусора. Значение GOGC по умолчанию равно 100, что означает, что сборка мусора будет запущена, когда объем новой памяти достигнет 100% от объема живой памяти
Рассмотрим пример программы и отследим изменение размера кучи с помощью инструмента go tool trace. Для запуска программы используем версию Go 1.20.1.
В данном примере, функция performMemoryIntensiveTask использует большое количество памяти размещаемой в куче. Данная функция запускает обработчик с размером очереди NumWorker и количество задач равное NumTasks.
package main
import (
"fmt"
"os"
"runtime/debug"
"runtime/trace"
"sync"
"time"
)
const (
NumWorkers = 4 // Количество воркеров.
NumTasks = 500 // Количество задач.
MemoryIntense = 10000 // Размер память затратной задачи (число элементов).
)
func main() {
// Запись в trace файл.
f, _ := os.Create("trace.out")
trace.Start(f)
defer trace.Stop()
// Установка целевого процента сборщика мусора. По умолчанию 100%.
debug.SetGCPercent(100)
// Очередь задач и очередь результата.
taskQueue := make(chan int, NumTasks)
resultQueue := make(chan int, NumTasks)
// Запуск воркеров.
var wg sync.WaitGroup
wg.Add(NumWorkers)
for i := 0; i < NumWorkers; i++ {
go worker(taskQueue, resultQueue, &wg)
}
// Отправка задач в очередь.
for i := 0; i < NumTasks; i++ {
taskQueue <- i
}
close(taskQueue)
// Получение результатов из очереди.
go func() {
wg.Wait()
close(resultQueue)
}()
// Обработка результатов.
for result := range resultQueue {
fmt.Println("Результат:", result)
}
fmt.Println("Готово!")
}
// Функция воркера.
func worker(tasks <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for task := range tasks {
result := performMemoryIntensiveTask(task)
results <- result
}
}
// performMemoryIntensiveTask функция требующая много памяти.
func performMemoryIntensiveTask(task int) int {
// Создание среза большого размера.
data := make([]int, MemoryIntense)
for i := 0; i < MemoryIntense; i++ {
data[i] = i + task
}
// Имитация временной задержки
time.Sleep(10 * time.Millisecond)
// Вычисление результата.
result := 0
for _, value := range data {
result += value
}
return result
}
Для трассировки работы программы результат записывается в файл trace.out:
// Запись в trace файл.
f, _ := os.Create("trace.out")
trace.Start(f)
defer trace.Stop()
Используя инструмент go tool trace, мы можем наблюдать за изменениями размера кучи и анализировать поведение сборщика мусора в вашей программе.
Hidden text
Обратите внимание, что точные детали и возможности инструмента go tool trace могут варьироваться в разных версиях Go, поэтому рекомендуется обратиться к официальной документации для получения более подробной информации о его использовании в вашей конкретной версии Go.
▪Статья
@golang_interview
package main
import "fmt"
func sum(a, b any) any {
return a + b
}
func main() {
fmt.Println(sum(2, 3))
}
📌Ответ
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет код ?
Anonymous Quiz
2%
1.5
92%
invalid operation: operator + not defined on a (variable of type any)
2%
0
4%
Ничего
Также известно, что при рекурсивном обходе узла за узлом у нас будет доступ только к конкретному узлу и к следующему за ним. Это признак общего паттерна, применяемого при работе с рекурсивными функциями – нужно уметь ориентироваться в более широком контексте.
Для этого во многих рекурсивных функциях предусмотрены дополнительные аргументы, действующие в качестве флагов в тех ситуациях, когда на предыдущем или последующем уровне выполняются определённые условия.
В контексте поставленной задачи давайте продумаем каждую ситуацию, в которой может оказаться узел, и как она соотносится с фактом потенциального дублирования конкретного значения:
•Недублирующийся узел указывает на дублирующийся узел
•Дублирующийся узел указывает на дублирующийся узел
•Недублирующийся узел указывает на дублирующийся узел
•Дублирующийся узел указывает на недублирующийся узел
На первый взгляд кажется, что эта задача легко решаема при помощи рекурсивной функции – нужно только обеспечить, чтобы она дошла прямым ходом до конца списка, не пропуская никакого состояния на вышестоящие уровни. Таким образом, первый из вышеперечисленных случаев пропускаем. Во втором случае перезаписываем указатель актуального узла. Третий случай вновь пропускаем. В четвёртом случае ещё раз перезаписываем.
Но задумайтесь, что случится, если вы достигнете конечного (nil), имея строку дублей. Допустим, мы работаем с 2 -> 3 -> 3 -> nil, давайте разберём вышеприведённые случаи узел за узлом:
2 -> 3
2 не равно 3, поэтому здесь мы никаких изменений в узел вносить не будем и вновь вызовем функцию, на этот раз передав ей в качестве аргумента узел '3'.
3 -> 3
a b
Здесь значения равны, и нам нужно убрать дубли. К счастью, поскольку в связных списках содержатся указатели, мы можем изменить исходный список, даже не обращаясь напрямую к головному узлу.
В данном случае мы можем перезаписать указатель 'a', так, чтобы он стал 'b' – в сущности, удалив 'a'. Теперь снова вызываем функцию, на этот раз передав ей узел 'b'.
3 -> nil
b
Как только мы достигнем
nil
, имея дубль, нам придётся попытаться перезаписать указатель, но мы не сможем — Go выдаст панику, поскольку нельзя присвоить указателю nil. Поэтому нам понадобится реализовать определённую логику, которая позволяла бы перехватывать ситуацию до возникновения паники, и просто возвращать nil, а не перезаписывать с заменой на nil. Но, если мы вернём nil, то всплывём на уровень вверх. Так мы не только потеряем контекст, позволявший судить, является ли данное значение дублем, но и не сможем изменять значение выше по рекурсивной цепочке, поскольку мы не меняли указатель напрямую.Вот что можно сделать для решения этой проблемы: мы можем не только полагаться на флаг, сигнализирующий о дубле и посылаемый вниз по пути с рекурсивным изменением. Вдобавок давайте создадим флаг, сигнализирующий, не всплыли ли мы вверх с того уровня, где было дублирующееся значение, смежное с
nil
. Таким образом, у нас сохранится уловка, позволяющая добраться до nil
, и вместе с тем мы сможем безопасно перезаписывать указатели. А если бы мы достигли уровня, имея этот флаг со значением true, мы переключаем узлы и устанавливаем его в false – так сообщается, что дубля в конце у нас уже нет.📌Решение
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Сложность задачи: Средняя
Условие задачи:
Дан массив интервалов времени проведения совещаний, intervals, где intervals[i] = [start(i), end(i)]. Найдите минимальное требуемое количество конференц-залов.
Пример:
Ввод:
intervals = [[0,30],[5,10],[15,20]]
Вывод: 2
Ввод: intervals = [[7,10],[2,4]]
Вывод: 1
📌РешениеПишите свое решение в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Условие: Имеется n городов, соединенных некоторым количеством рейсов. Вам дан массив flights, где flights[i] = [fromi, toi, pricei] означает, что существует рейс из города fromi в город toi со стоимостью pricei.
Также даны три целых числа src, dst и k, возвращаем самую дешевую цену из src в dst с не более чем k остановками. Если такого маршрута не существует, возвращается -1.
Пример:
Ввод: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
Вывод: 700
Ввод: n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1
Вывод: 200
Решение
Пишите свое решение в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Вы являетесь менеджером баскетбольной команды. Для участия в предстоящем турнире Вы хотите выбрать команду, набравшую наибольшее количество очков. Показатель команды складывается из суммы показателей всех игроков команды.
Однако в баскетбольной команде не должно быть конфликтов. Конфликт возникает, если младший игрок набрал строго больше очков, чем старший. Конфликт не возникает между игроками одного возраста.
Задав два списка, scores и ages, в которых каждый scores[i] и ages[i] представляет собой счет и возраст i-го игрока соответственно, верните наибольший общий балл среди всех возможных баскетбольных команд.
Пример:
Ввод: scores = [1,3,5,10,15], ages = [1,2,3,4,5]
Вывод: 34
Ввод: scores = [4,5,6,5], ages = [2,1,2,1]
Вывод: 16
Пишите свое решение в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
При разработке Golang приложений необходимо учитывать следующие рекомендации по безопасности:
▪Валидация ввода: Никогда не доверяйте входным данным. Всегда проводите валидацию и фильтрацию пользовательского ввода, чтобы предотвратить атаки типа SQL-инъекции, XSS и другие уязвимости.
▪Защита от переполнения буфера: Обязательно проверяйте размеры буферов и массивов при обработке данных. Используйте безопасные функции для работы с памятью, чтобы предотвратить переполнение буфера.
▪Использование параметризованных запросов: При работе с базами данных используйте параметризованные запросы, чтобы избежать SQL-инъекций. Никогда не создавайте запросы, включающие пользовательский ввод напрямую.
▪Защита от утечек памяти: Убедитесь, что ваши приложения Golang не страдают от утечек памяти. Правильно управляйте ресурсами и освобождайте память после использования.
▪Шифрование данных: При передаче и хранении конфиденциальных данных используйте шифрование для защиты данных от несанкционированного доступа.
▪Обновление зависимостей: Регулярно обновляйте зависимости в ваших Golang приложениях, чтобы исправить уязвимости и получить последние исправления ошибок.
Соблюдение этих рекомендаций поможет повысить безопасность ваших Golang приложений и защитить их от потенциальных атак.
Пишите свой ответ в комментариях👇
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Стандартный профайлер в Go имеет некоторый незначительный overhead, который может оказать влияние на производительность вашего приложения. Однако этот overhead обычно незначительный и не должен существенно замедлять ваше приложение.
Встроенный профайлер в Go использует счетчики аппаратного процессора для сбора информации о производительности. Это означает, что при использовании профайлера будет некоторое количество дополнительных инструкций процессора, которые потребуются для сбора этой информации.
Влияние профайлера на производительность может быть усилено, если ваше приложение уже работает с высокой интенсивностью процессора или имеет высокую нагрузку на память. В таких случаях, профайлирование может увеличить нагрузку на процессор и память, что может привести к замедлению выполнения вашего приложения.
Однако, стоит отметить, что overhead от профайлера обычно не является значительным и не должен быть проблемой в большинстве случаев. Если вы обнаружите, что профайлер существенно замедляет ваше приложение, то, возможно, имеет смысл использовать его только во время отладки и разработки, а не в продакшн-среде.
Если вы хотите более точно измерить overhead профайлера в вашем конкретном случае, вы можете использовать инструменты профилирования, такие как go tool
pprof
, чтобы анализировать профилировочные данные и определить, какое влияние профайлер оказывает на производительность вашего приложения.В целом, стандартный профайлер в Go предоставляет ценную информацию о производительности вашего приложения, и его overhead обычно не является значительным. Однако, стоит оценить его использование в зависимости от конкретной ситуации и требований вашего приложения.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
https://go.dev/blog/pgo
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
go.dev
Profile-guided optimization in Go 1.21 - The Go Programming Language
Introduction to profile-guided optimization, generally available in Go 1.21.
🎉 Релиз Go 1.21.1 и 1.20.8
🔐 Новые релизы включают исправления безопасности для cmd/go (CVE-2023-39320), html/template (CVE-2023-39318, CVE-2023-39319) и crypto/tls.
🗣 Announcement: https://groups.google.com/g/golang-announce/c/Fm51GRLNRvM
⬇️ Загрузить: https://go.dev/dl/#go1.21.1
@golang_interview
🔐 Новые релизы включают исправления безопасности для cmd/go (CVE-2023-39320), html/template (CVE-2023-39318, CVE-2023-39319) и crypto/tls.
🗣 Announcement: https://groups.google.com/g/golang-announce/c/Fm51GRLNRvM
⬇️ Загрузить: https://go.dev/dl/#go1.21.1
@golang_interview