Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
382 - Telegram Web
Telegram Web
👩‍💻 errors.Is(), errors.As(), errors.Unwrap(), кастомные ошибки и многое другое: подробное руководство для Go-разработчика

👉 Читать
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
💬 Почему использование chan struct{} вместо chan bool предпочтительнее для сигнализации между горутинами?

🔹
chan struct{} сразу показывает, что канал используется исключительно для сигнализации, тогда как chan bool может вызвать путаницу, так как значения true и false могут иметь разный смысл.

🔹 Тип struct{} не занимает памяти — это просто сигнал. Это приводит к небольшой, но все равно оптимизации памяти.

🔹 chan struct{} исключает возможность неправильного использования канала для передачи данных, что может произойти при использовании chan bool.

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

📌 Пример:

type JobDispatcher struct {
start chan struct{}
}

func NewJobDispatcher() *JobDispatcher {
return &JobDispatcher{
start: make(chan struct{}),
}
}

func (j *JobDispatcher) Start() {
close(j.start)
}
👍18
💬 Как можно оптимизировать многократные вызовы одной и той же функции в Go, чтобы избежать выполнения одной и той же работы несколько раз?

Можно использовать пакет singleflight. Он гарантирует, что независимо от того, сколько раз вызывается функция в один и тот же период, она будет выполнена только один раз, и результат этого вызова будет возвращен всем вызывающим.

📌 Пример использования:


var group singleflight.Group

func UsingSingleFlight(key string) {
v, _, _ := group.Do(key, func() (any, error) {
return FetchExpensiveData()
})

fmt.Println(v)
}


В этом примере singleflight.Group оборачивает вызов функции внутри метода group.Do(), который проверяет, был ли тот же ключ уже запрошен. Если да, он ждет результата первоначального вызова и возвращает его всем вызывающим.

Основное преимущество использования singleflight заключается в том, что он предотвращает многократное выполнение одной и той же работы, что особенно полезно для ресурсоемких операций или операций, которые нельзя выполнять одновременно (например, ping() на сервер). В отличие от кеша, singleflight не только сохраняет результаты, а также координирует выполнение функции.
👍131
💬 Как использовать context.AfterFunc для выполнения функции после отмены контекста и что происходит, если контекст уже отменен?

В Go функция context.AfterFunc (Go 1.21 +) позволяет запланировать выполнение функции после завершения контекста, будь то из-за отмены или тайм-аута. Она запускает функцию в новой горутине сразу после того, как канал ctx.Done родительского контекста отправляет сигнал.

📌 Пример использования:


ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()

stop := context.AfterFunc(ctx, func() {
fmt.Println("Cleanup operations after context is done")
})


Если контекст уже отменен на момент вызова AfterFunc, функция f будет выполнена немедленно в новой горутине.

Функция stop() позволяет отменить запланированную функцию, если она еще не начала выполняться. Если stop() возвращает true, это означает, что функция была успешно остановлена до выполнения. Если stop() возвращает false, это означает, что функция уже начала выполняться или была остановлена ранее.

📌 Пример использования stop():


stop := context.AfterFunc(ctx, func() {
// some cleanup code
})

if stopped := stop(); stopped {
fmt.Println("Remove the callback before context is done")
}


Функция AfterFunc полезна для выполнения задач очистки, логирования или других операций, которые необходимо выполнить после отмены контекста.
👍12
💬 Почему использование time.Sleep() может быть проблематичным в Go-программах, и как можно улучшить управление паузами, чтобы учитывать контекст выполнения?

Использование time.Sleep() может быть проблематичным, потому что оно не учитывает контекст выполнения и не может быть прервано. Например, если приложение получает сигнал на завершение работы, функция, использующая time.Sleep(), не сможет сразу прекратить выполнение, а продолжит выполнение только после завершения периода сна. Это может привести к задержкам в завершении работы приложения и другим проблемам.

Чтобы улучшить управление паузами и учитывать контекст выполнения, лучше использовать конструкции, которые могут реагировать на сигналы контекста. Например, можно использовать функцию time.After() в сочетании с select, чтобы обрабатывать паузы и проверку контекста:

func doWork(ctx context.Context, d time.Duration) {
for {
select {
case <-ctx.Done():
return
case <-time.After(d):
}

...
}
}


Также можно использовать time.Timer для более эффективного управления таймерами:

func doWork(ctx context.Context, d time.Duration) {
delay := time.NewTimer(d)

for {
select {
case <-ctx.Done():
if !delay.Stop() {
<-delay.C
}
return
case <-delay.C:
_ = delay.Reset(d)
}

...
}
}


Этот подход позволяет функции немедленно завершиться при получении сигнала завершения контекста, предотвращая утечки памяти и обеспечивая более предсказуемое поведение программы.
👍13🤔1
✉️ Как завалить собеседование, даже не начав его: 8 ошибок в сопроводительных письмах

Откликаетесь, но сразу получаете отказы? Не торопитесь с выводами — возможно, все дело в вашем сопроводительном письме.

👉Сопроводительное — это первое впечатление, которое мы производим на эйчара, а первое впечатление, как известно, очень важно.

Собрали для вас несколько распространенных ошибок по составлению такого письма — а в статье по ссылке можно найти остальные ошибки и пример идеального сопроводительного.

Кстати, вакансии можно поискать в наших профильных каналах:
🤮Data Science, анализ данных, аналитика
🤮Python
🤮Frontend
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
💬 Почему важно следить за временем жизни горутин и как мы можем избежать проблем с утечкой памяти в Go?

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

📌 Чтобы избежать проблем с утечкой памяти, необходимо:

1. Использовать контексты (context.Context): контексты позволяют контролировать время выполнения горутины и отменять её выполнение, когда это необходимо. Например, использование select с контекстом позволяет горутине завершиться корректно при получении сигнала отмены:

func Job(ctx context.Context, d time.Duration) {
for {
select {
case <-ctx.Done():
return
default:
...
time.Sleep(d)
}
}
}


2. Закрывать каналы: если горутина читает данные из канала, важно корректно закрывать этот канал, чтобы горутина завершалась и не зависала бесконечно.

func worker(jobs <-chan int) {
for i := range jobs {
...
}
}

jobs := make(chan int)
go worker(jobs)
// Закрытие канала, когда работа завершена
close(jobs)


3. Избегать использования time.Sleep() без контекста: функция time.Sleep() не поддерживает прерывания и может привести к зависанию горутины, если её необходимо завершить. Вместо этого используйте конструкции, учитывающие контекст, такие как time.After с select.
👍82
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 Как отключить поддержку HTTP/2 на стороне клиента и сервера в Go? Почему это может понадобиться?

Можно использовать переменную окружения GODEBUG. Она позволяет управлять выполнением определенных частей программы Go.

Для отключения HTTP/2 необходимо установить GODEBUG следующим образом:

export GODEBUG=http2client=0,http2server=0


Эта команда отключит поддержку HTTP/2 по умолчанию как в HTTP-клиенте, так и в HTTP-сервере. Это может быть полезно в случае, если есть проблемы с реализацией HTTP/2 на сервере или если необходимо поддерживать совместимость с более старыми системами, которые не поддерживают HTTP/2.

При запуске программы Go с такими параметрами GODEBUG, программа будет использовать только HTTP/1.1 для всех HTTP-запросов и ответов, обходя любые потенциальные проблемы, связанные с HTTP/2.

👉 Подробнее
👍141
💬 Почему лучше использовать неэкспортируемую пустую структуру в качестве ключа контекста в Go вместо строки или другого примитивного типа?

Использование неэкспортируемой пустой структуры в качестве ключа контекста в Go предпочтительнее по нескольким причинам:

1. Уникальность: пустая структура обеспечивает уникальность в пределах области видимости пакета, что помогает избежать конфликтов, которые могут возникнуть при использовании строк или других примитивных типов в качестве ключей.
2. Легковесность: пустая структура не выделяет памяти, так как она не содержит полей, что делает ее очень легким и эффективным вариантом для использования в качестве ключа.
3. Избежание конфликтов: использование пустых структур помогает избежать конфликтов с другими пакетами, которые могут случайно использовать те же самые строки или примитивные типы в качестве ключей контекста.

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


type contextKey struct{}

func main() {
ctx := context.WithValue(
context.Background(),
contextKey{}, "данные, связанные с запросом",
)

handleRequest(ctx)
}

func handleRequest(ctx context.Context) {
fmt.Println("data:", ctx.Value(contextKey{}))
}


Этот пример демонстрирует, как использование пустой структуры в качестве ключа контекста помогает обеспечить уникальность и избежать потенциальных конфликтов.
👍162
💬 Почему в Go лучше использовать strconv вместо fmt для преобразования в/из строки?

Пакет strconv специально создан для преобразования строк, что означает, что он оптимизирован именно для них.

Для наглядности рассмотрим простое сравнение производительности:


func BenchmarkFmt(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprint(i)
}
}

func BenchmarkStrconv(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = strconv.Itoa(i)
}
}

BenchmarkFmt-8 23821753 50.17 ns/op 16 B/op 2 allocs/op
BenchmarkStrconv-8 100000000 11.47 ns/op 3 B/op 1 allocs/op


strconv.Itoa значительно быстрее и эффективнее с точки зрения выделения памяти по сравнению с fmt.Sprint. fmt.Sprint при этом использует рефлексию, чтобы понять, с каким типом данных работает, и определяет лучший способ форматирования его как строки.

Процесс рефлексии не «бесплатный», он добавляет как время, так и накладные расходы на память, что может быть довольно значительным, когда мы обрабатываем большие объемы данных или требуется высокая производительность.
👍203
💬 Что произойдет, если в type switch использовать временную переменную для типа nil? Какой тип будет у этой переменной?

Когда в type switch используется временная переменная для типа nil, тип этой переменной будет таким же, как и тип исходного значения, которое мы проверяем в TypeSwitchGuard. Например, если исходное значение имеет тип any, временная переменная также будет иметь тип any. Это можно проиллюстрировать следующим примером:
var x any
var y error

switch t := x.(type) {
case nil:
y = t // Ошибка компиляции: any does not implement error
}

В этом примере код не компилируется с ошибкой, указывающей, что переменная типа any не может быть присвоена переменной типа error, так как тип any не реализует метод Error. Это подтверждает, что временная переменная t в случае nil имеет тот же тип, что и x (в данном случае any).
1
Ответьте на 3 вопроса, чтобы получить вводные занятия к курсу «Алгоритмы и структуры данных»

🔥Получите вводные занятия, ответив на 3 вопроса – https://proglib.io/w/c2161ff4

На вводной части вас ждут:

1. Лекция «Производительность алгоритмов» от руководителя разработки Яндекс.Самокатов

2. Лекция «Итеративные сортировки и линейные сортировки» от аспирант департамента искусственного интеллекта ВШЭ

3. Практические задания после лекций

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

⚡️Переходите и начинайте учиться уже сегодня – https://proglib.io/w/c2161ff4
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
💬 Поддерживается ли в Go арифметика указателей как C++ или других языках?

В Go, в отличие от других языков, таких как C++, арифметика указателей не поддерживается напрямую. К примеру, нельзя прибавить или вычесть числа непосредственно у указателя, перемещая его вдоль блока памяти.

Отсутствие арифметики указателей исключает целый класс ошибок, связанных с выходом за границы массива, неправильным обращением к памяти и другими подобными проблемами. Это помогает предотвратить баги и уязвимости, связанные с прямым доступом и изменением адресов памяти.

Для выполнения операций, аналогичных арифметике указателей, в Go можно использовать слайсы, которые обеспечивают безопасный доступ к элементам массива и автоматически управляют размером и ёмкостью.
🔥1
💬 Когда pointer ресивер предпочтительнее использовать, чем value ресивер в Go?

Первая причина — чтобы метод мог изменить значение, на которое указывает его ресивер.

Вторая — чтобы избежать копирования значения при каждом вызове метода. Это может быть более эффективно, если ресивер, например, является большой структурой.

В примере ниже, оба метода Scale и Abs имеют тип ресивера *Vertex, хотя метод Abs не должен изменять свой ресивер.


package main

import (
"fmt"
"math"
)

type Vertex struct {
X, Y float64
}

func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
v := &Vertex{3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}


В общем случае, все методы для данного типа должны использовать либо только pointer ресивер, либо только value ресивер, чтобы избежать путаницы и обеспечить согласованность.
👍31
⚡️Proglib запускает канал про ИИ для генерации звука

Там мы будем рассказывать про все существующие нейросети, которые генерируют музыку и голос — с пошаговыми инструкциями, инструментами и лайфхаками.

⭐️генерация голоса и музыки
⭐️замена и перевод речи
⭐️распознавание звуков

👉Подписывайтесь!
💬 Интерфейс и any (interface{}) в Go — это одно и то же? Объясните простыми словами.

Нет, это не одно и то же. Интерфейсы определяют контракты для типов, которые их реализуют.

any — это псевдоним для пустого интерфейса interface{}. Пустой интерфейс interface{} может содержать значение любого типа, поскольку он не требует реализации никаких методов.
🥱5👍3
2025/07/13 10:38:14
Back to Top
HTML Embed Code: