Anonymous Quiz
30%
Значение по умолчанию для типа
22%
Ошибка времени выполнения
24%
Значение переменной до приведения
24%
nil
👍1
Хэш-коллизия — это случай, когда два разных входных значения генерируют один и тот же хэш-код. Это происходит из-за ограниченного числа возможных хэш-значений, которые могут привести к повторениям при большом количестве входных данных.
Принимает входные данные (например, строку или целое число) и возвращает фиксированное значение, которое обычно используется для индексирования массива или другого контейнера данных. Однако, поскольку количество возможных входных данных потенциально бесконечно, а количество возможных выходных значений хэш-функции ограничено, неизбежно возникают ситуации, когда разные входные данные производят одинаковое хэш-значение. Это и называется хэш-коллизией. Представим, что у нас есть простая хэш-функция для строк, которая возвращает длину строки в качестве хэш-значения. Для строк "cat" и "dog" хэш-значение будет одинаковым (3), что приводит к коллизии.
Существует несколько методов для управления хэш-коллизиями. Два наиболее распространенных метода — это цепочки (chaining) и открытая адресация (open addressing).
В этом методе каждая ячейка хэш-таблицы содержит указатель на список (например, связанный список) всех элементов, которые имеют одно и то же хэш-значение. Когда происходит коллизия, новый элемент просто добавляется в этот список.
type Entry struct {
key string
value int
next *Entry
}
type HashMap struct {
buckets []*Entry
}
func (m *HashMap) Put(key string, value int) {
index := hash(key) % len(m.buckets)
entry := m.buckets[index]
for entry != nil {
if entry.key == key {
entry.value = value
return
}
entry = entry.next
}
m.buckets[index] = &Entry{key: key, value: value, next: m.buckets[index]}
}
func hash(key string) int {
hash := 0
for _, char := range key {
hash += int(char)
}
return hash
}
В этом методе все элементы хранятся непосредственно в хэш-таблице. Если ячейка, определенная хэш-функцией, уже занята, используется альтернативная стратегия для нахождения следующей доступной ячейки. Наиболее распространенные стратегии включают линейное пробирование (linear probing), квадратичное пробирование (quadratic probing) и двойное хеширование (double hashing).
type HashMap struct {
keys []string
values []int
size int
}
func (m *HashMap) Put(key string, value int) {
index := hash(key) % len(m.keys)
for m.keys[index] != "" {
if m.keys[index] == key {
m.values[index] = value
return
}
index = (index + 1) % len(m.keys)
}
m.keys[index] = key
m.values[index] = value
m.size++
}
func hash(key string) int {
hash := 0
for _, char := range key {
hash += int(char)
}
return hash
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Anonymous Quiz
13%
Объявить тип и явно указать интерфейсы
68%
Просто объявить методы интерфейса для типа
4%
Использовать ключевое слово implements
15%
Создать структуру, содержащую интерфейс
HTTP/3 — это последняя версия протокола HTTP, предназначенная для передачи данных в интернете. Эта версия включает несколько значительных улучшений по сравнению с предыдущими версиями, в частности благодаря использованию протокола QUIC.
QUIC (Quick UDP Internet Connections) разработан Google и работает поверх UDP, а не TCP. Обеспечить более быструю и надежную передачу данных, улучшить производительность и сократить задержки.
QUIC значительно сокращает время на установление соединения по сравнению с TCP. Благодаря интеграции с TLS, процесс безопасности и установка соединения происходят одновременно.
В HTTP/3 каждый поток данных передается независимо, что предотвращает блокировку одного потока из-за потери пакетов в другом потоке, что является недостатком HTTP/2.
HTTP/3 позволяет отправлять несколько запросов и получать ответы через одно соединение одновременно без блокировок, что ускоряет передачу данных и повышает эффективность использования соединений.
Новый механизм сжатия заголовков, улучшенный по сравнению с HPACK в HTTP/2, который учитывает особенности QUIC и уменьшает задержки.
Как и в HTTP/2, HTTP/3 поддерживает серверное push-сообщение, позволяя серверу отправлять данные клиенту до их запроса, что ускоряет загрузку страниц.
Быстрое установление соединений и устойчивость к потерям пакетов делают HTTP/3 значительно быстрее, особенно в условиях ненадежных сетей.
Независимая передача потоков данных и улучшенное мультиплексирование снижают задержки при загрузке страниц и передачи данных.
Улучшенная устойчивость к сетевым сбоям и потерям пакетов делает соединения более надежными и стабильными.
Поскольку HTTP/3 использует QUIC и UDP, а не TCP, некоторые старые или ограниченные сети и устройства могут не поддерживать этот протокол.
Внедрение и поддержка HTTP/3 требуют новых знаний и навыков, что может усложнить разработку и администрирование.
Переход на HTTP/3 может требовать обновления серверного оборудования и программного обеспечения для полной поддержки нового протокола.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Anonymous Quiz
25%
hashable
65%
comparable
8%
keyable
3%
equatable
Это технология, используемая для изменения сетевых адресов в заголовках пакетов данных, которые проходят через маршрутизатор или межсетевой экран. Она позволяет нескольким устройствам в локальной сети использовать один и тот же публичный IP-адрес для выхода в интернет.
Фиксированный сопоставление: Один внутренний IP-адрес сопоставляется с одним внешним IP-адресом. Используется, когда необходимо, чтобы устройство в локальной сети всегда было доступно под одним и тем же публичным IP-адресом. Например Веб-сервер, который должен быть доступен из интернета под фиксированным IP-адресом.
Внутренние IP-адреса сопоставляются с пулом внешних IP-адресов. Когда внутреннее устройство инициирует соединение с интернетом, ему временно присваивается один из доступных внешних IP-адресов. Например, локальная сеть с большим количеством устройств, где не требуется фиксированный внешний IP-адрес для каждого устройства.
Несколько внутренних IP-адресов могут использовать один внешний IP-адрес, но различаются по номерам портов. Каждый внутренний IP-адрес и порт сопоставляется с уникальным внешним портом. Например, Домашние или офисные сети, где множество устройств выходят в интернет через один публичный IP-адрес.
IPv4-адресов недостаточно для всех устройств, и NAT позволяет использовать один публичный IP-адрес для множества устройств.
Внутренние IP-адреса не видны извне, что усложняет потенциальным злоумышленникам попытки атак на внутренние устройства.
NAT позволяет администрировать и контролировать сетевой трафик, предоставляя возможности для управления доступом и приоритизацией трафика.
Когда устройство в локальной сети (например, компьютер с IP-адресом 192.168.1.10) инициирует соединение с устройством в интернете, NAT изменяет исходящий IP-адрес и порт на внешний IP-адрес маршрутизатора и уникальный номер порта.
Когда ответный пакет возвращается, NAT использует таблицу сопоставлений, чтобы определить, к какому внутреннему устройству направить пакет, и изменяет внешний IP-адрес и порт обратно на внутренний IP-адрес и порт.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2🔥1
Anonymous Quiz
71%
func f() (result int)
9%
func f() (result: int)
16%
func f() int result
4%
func f() (result = int)
👍1
Отладка протокола Protocol Buffers (protobuf) может быть сложной задачей, особенно если вы работаете с бинарным форматом данных. Тем не менее, существует несколько шагов и инструментов, которые могут помочь вам в этом процессе. Вот некоторые из них:
Protocol Buffers поддерживают сериализацию данных в текстовом формате, который проще для чтения и отладки. Вы можете конвертировать бинарные данные в текстовый формат для более удобной отладки.
// message.proto
syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
}
// main.go
package main
import (
"fmt"
"log"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"your_project_path/your_proto_package" // заменить на реальный путь
)
func main() {
person := &your_proto_package.Person{
Name: "John Doe",
Id: 123,
Email: "john.doe@example.com",
}
// Сериализация в бинарный формат
data, err := proto.Marshal(person)
if err != nil {
log.Fatalf("Failed to marshal: %v", err)
}
// Десериализация обратно в текстовый формат для отладки
person2 := &your_proto_package.Person{}
err = proto.Unmarshal(data, person2)
if err != nil {
log.Fatalf("Failed to unmarshal: %v", err)
}
jsonString, err := protojson.Marshal(person2)
if err != nil {
log.Fatalf("Failed to marshal to JSON: %v", err)
}
fmt.Println(string(jsonString))
}
protoc: Официальный компилятор protobuf, который может генерировать текстовые представления сообщений.
protoc-gen-json: Плагин для protoc, который позволяет сериализовать сообщения в формат JSON.
protoc-inspector: Утилита для визуализации и отладки protobuf сообщений.
Убедитесь, что ваша
.proto
схема правильна и соответствует структуре данных, которую вы пытаетесь сериализовать и десериализовать. Ошибки в схеме могут привести к неправильной сериализации и десериализации данных.Добавление логирования и трассировки в код может помочь отслеживать, где происходят ошибки при работе с protobuf.
// main.go
package main
import (
"fmt"
"log"
"google.golang.org/protobuf/proto"
"your_project_path/your_proto_package" // заменить на реальный путь
)
func main() {
person := &your_proto_package.Person{
Name: "John Doe",
Id: 123,
Email: "john.doe@example.com",
}
// Логируем данные до сериализации
fmt.Printf("Before Marshal: %+v\n", person)
// Сериализация в бинарный формат
data, err := proto.Marshal(person)
if err != nil {
log.Fatalf("Failed to marshal: %v", err)
}
// Логируем бинарные данные
fmt.Printf("Binary data: %v\n", data)
// Десериализация
person2 := &your_proto_package.Person{}
err = proto.Unmarshal(data, person2)
if err != nil {
log.Fatalf("Failed to unmarshal: %v", err)
}
// Логируем данные после десериализации
fmt.Printf("After Unmarshal: %+v\n", person2)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Anonymous Quiz
2%
GC полностью ручной и не влияет на производительность
87%
GC автоматически управляет памятью, что может временно замедлить выполнение программы
7%
GC удаляет только глобальные переменные и не влияет на локальные переменные
4%
GC управляет только статической памятью
👍1
HTTP (HyperText Transfer Protocol) — это протокол, используемый для передачи данных в интернете.
Год выпуска: 1991
Особенности
Первая версия HTTP, очень простая. Поддерживала только GET-запросы. Отсутствие заголовков, только один объект мог быть передан в ответ на запрос.
Использование:
В настоящее время практически не используется.
Год выпуска: 1996
Особенности
Введены методы запроса, такие как GET, POST и HEAD. Поддержка заголовков для метаданных. Каждый запрос/ответ требует нового соединения, что делает передачу данных менее эффективной.
Использование
Исторически важен, но также почти не используется в современных приложениях.
Год выпуска: 1997
Особенности
Поддержка устойчивых (persistent) соединений, что позволяет повторное использование одного соединения для нескольких запросов/ответов. Введены дополнительные методы запросов, такие как OPTIONS, PUT, DELETE, TRACE и CONNECT. Поддержка chuncked transfer encoding для передачи данных по частям. Улучшена работа с кэшированием и аутентификацией.
Использование
Широко используется и в настоящее время, хотя многие системы переходят на HTTP/2.
Год выпуска: 2015
Особенности
Бинарный протокол, что улучшает производительность и уменьшает количество ошибок. Поддержка мультиплексирования, что позволяет отправлять несколько запросов через одно соединение одновременно, уменьшая задержки. Сжатие заголовков, что уменьшает объем передаваемых данных. Серверное push-сообщение (server push), позволяющее серверу отправлять данные клиенту до того, как он их запросит.
Использование
Быстро набирает популярность благодаря улучшенной производительности и эффективности.
Год выпуска: 2022 (черновая версия в 2020)
Особенности
Основан на протоколе QUIC, который работает поверх UDP, а не TCP. Поддержка улучшенного мультиплексирования и быстрого установления соединений. Лучшая устойчивость к потерям пакетов и более высокая скорость передачи данных по сравнению с HTTP/2.
Использование
Внедрение продолжается, но многие крупные интернет-компании, такие как Google и Facebook, уже активно используют HTTP/3.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Anonymous Quiz
93%
Массивы имеют фиксированный размер, а слайсы могут изменять размер
3%
Слайсы могут содержать элементы разных типов, а массивы - только одного типа
1%
Массивы могут быть переданы по ссылке, а слайсы - только по значению
2%
Слайсы хранятся в памяти на стеке, а массивы - в куче
👍1
Весь код находится в одном проекте, что упрощает понимание, разработку и отладку. Разработчики могут легко работать с общей кодовой базой.
Приложение разворачивается как единое целое, что упрощает процесс развертывания. Нет необходимости координировать развертывание множества сервисов.
Взаимодействие между компонентами происходит внутри одного процесса, что устраняет сетевые задержки и обеспечивает более быструю работу.
Все компоненты приложения имеют доступ к одной базе данных, что упрощает управление транзакциями и консистентностью данных.
Поскольку приложение развертывается как единое целое, инфраструктурные расходы на управление сетью, оркестрацию и мониторинг меньше по сравнению с микросервисной архитектурой.
Масштабировать приложение приходится целиком, что может быть неэффективно. Если только одна часть приложения испытывает высокую нагрузку, всю систему нужно масштабировать, что приводит к избыточным затратам.
По мере роста приложения кодовая база становится более сложной, что затрудняет поддержку и внесение изменений. Даже небольшие изменения могут потребовать повторного тестирования и развертывания всего приложения.
Все компоненты должны использовать одну и ту же технологическую платформу, что ограничивает возможность выбора лучших инструментов и фреймворков для разных частей приложения.
Развертывание монолитного приложения может занять больше времени, особенно если оно стало большим и сложным. Это замедляет процесс выпуска обновлений.
Высокая степень связанности компонентов может привести к проблемам, когда сбой в одном компоненте может повлиять на всю систему.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
Anonymous Quiz
90%
С помощью статической типизации и строгой проверки типов на этапе компиляции
7%
С помощью динамической типизации и проверок во время выполнения
2%
С помощью использования только встроенных типов данных
1%
С помощью глобальной блокировки
👍1
Легко масштабировать отдельные компоненты системы независимо друг от друга. Например, если один микросервис испытывает высокую нагрузку, его можно масштабировать, не затрагивая другие части системы.
Каждый микросервис может разрабатываться, тестироваться и развертываться независимо от других, что сокращает время разработки и улучшает скорость выпуска обновлений.
Разработчики могут использовать разные технологии, языки программирования и фреймворки для разных микросервисов, выбирая наиболее подходящие инструменты для каждой конкретной задачи.
Проблемы в одном микросервисе не приводят к сбою всего приложения. Это повышает устойчивость системы в целом, так как сбои ограничены контекстом конкретного микросервиса.
Маленькие независимые команды могут работать над отдельными микросервисами, что повышает продуктивность и ускоряет разработку новых функций.
Система делится на более мелкие и управляемые части, что облегчает понимание кода и упрощает поддержку.
Управление множеством микросервисов требует эффективной оркестрации и мониторинга. Это приводит к необходимости использования сложных инструментов и дополнительных затрат на администрирование.
Взаимодействие между микросервисами происходит через сеть, что может привести к увеличению задержек и необходимости управления сетевой нагрузкой.
Разработка и тестирование распределённой системы сложнее, чем монолита. Требуется учитывать межсервисное взаимодействие, консистентность данных и возможные сбои в сети.
Разделение данных между микросервисами может привести к дублированию данных и усложнению управления транзакциями, особенно если нужна консистентность данных между сервисами.
Поддержание совместимости между различными микросервисами и обеспечение их корректного взаимодействия требует дополнительного контроля и тестирования.
Управление конфигурацией для множества микросервисов становится сложнее, так как каждая служба может иметь свои собственные настройки и зависимости.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Anonymous Quiz
2%
Интерфейсы увеличивают производительность программы
96%
Интерфейсы позволяют реализовать полиморфизм и упрощают тестирование
0%
Интерфейсы предотвращают утечки памяти
1%
Интерфейсы автоматически синхронизируют горутины
Передача слайсов в разные горутины в Go может быть как безопасной, так и небезопасной в зависимости от контекста использования. Давайте рассмотрим, почему это так, и какие подходы позволяют обеспечить безопасность.
Слайсы в Go являются ссылочными типами, что означает, что они содержат указатель на массив в памяти, длину и емкость. Если несколько горутин одновременно модифицируют один и тот же слайс или его элементы, это может привести к состояниям гонки, некорректным данным и другим непредсказуемым результатам.
Если слайс передается в горутины только для чтения, это безопасно. Одновременное чтение данных не вызывает конфликтов. В этом примере горутины только читают значения из слайса, что безопасно.
package main
import (
"fmt"
"sync"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
for _, v := range slice {
wg.Add(1)
go func(val int) {
defer wg.Done()
fmt.Println(val)
}(v)
}
wg.Wait()
}
Если каждая горутина должна иметь независимую копию данных, можно передать копию слайса. Это устраняет возможность конфликтов при записи.
package main
import (
"fmt"
"sync"
)
func main() {
originalSlice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
for _, v := range originalSlice {
wg.Add(1)
go func(val int) {
defer wg.Done()
newSlice := make([]int, len(originalSlice))
copy(newSlice, originalSlice)
newSlice[0] = val
fmt.Println(newSlice)
}(v)
}
wg.Wait()
}
Если горутины должны одновременно читать и модифицировать слайс, необходимо использовать механизмы синхронизации, такие как мьютексы или каналы, чтобы обеспечить безопасный доступ к данным.
package main
import (
"fmt"
"sync"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
var mu sync.Mutex
for i := range slice {
wg.Add(1)
go func(index int) {
defer wg.Done()
mu.Lock()
slice[index] *= 2
mu.Unlock()
}(i)
}
wg.Wait()
fmt.Println(slice)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Anonymous Quiz
95%
С помощью мьютексов и каналов
2%
С помощью глобальных переменных
1%
С помощью таймеров
2%
С помощью блокировок на уровне пакетов
РПС (RPC, Remote Procedure Call) — это технология, которая позволяет программе вызывать функции (процедуры) на удалённых машинах, как если бы они были локальными. В контексте программирования на Go, РПС используется для организации взаимодействия между разными частями распределённых систем.
В современных приложениях часто необходимо взаимодействовать с различными сервисами, которые могут находиться на разных серверах. РПС позволяет реализовать это взаимодействие простым и прозрачным способом.
В архитектуре микросервисов разные части системы выполняются как независимые сервисы. РПС обеспечивает эффективное и удобное взаимодействие между этими сервисами.
РПС позволяет распределить нагрузку между несколькими серверами, что повышает производительность и масштабируемость системы.
net/rpc
, а также сторонние библиотеки, такие как gRPC, которые обеспечивают более широкие возможности и поддержку разных протоколов.// Сервисная часть
package main
import (
"net"
"net/rpc"
)
// Определяем структуру и методы, которые будут доступны через RPC
type Arith int
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
type Args struct {
A, B int
}
func main() {
arith := new(Arith)
rpc.Register(arith)
listener, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal("Listen error: ", err)
}
rpc.Accept(listener)
}
Multiply
для умножения двух чисел, и клиентскую часть, которая вызывает этот метод на удалённом сервере.// Клиентская часть
package main
import (
"fmt"
"log"
"net/rpc"
)
type Args struct {
A, B int
}
func main() {
client, err := rpc.Dial("tcp", "localhost:1234")
if err != nil {
log.Fatal("Dialing error: ", err)
}
args := Args{2, 3}
var reply int
err = client.Call("Arith.Multiply", &args, &reply)
if err != nil {
log.Fatal("Arith error: ", err)
}
fmt.Printf("Result: %d\n", reply)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
Anonymous Quiz
2%
Пакеты увеличивают размер исполняемого файла
2%
Пакеты автоматически увеличивают производительность программы
3%
Пакеты устраняют необходимость в компиляции
93%
Пакеты помогают организовать код и повторно использовать его
😁3❤1