Всем привет!
Меня зовут Панасюк Игорь, данный канал посвящен моей школе igoroutine.courses. Здесь будут выходить разные анонсы, интересные задачи и новости.
Подробную информацию обо мне вы можете найти на сайте.
igoroutine_courses
The Nature of Programming
Меня зовут Панасюк Игорь, данный канал посвящен моей школе igoroutine.courses. Здесь будут выходить разные анонсы, интересные задачи и новости.
Подробную информацию обо мне вы можете найти на сайте.
igoroutine_courses
The Nature of Programming
1🔥6❤5👍4⚡1
The Nature of Concurrency — курс, который посвящён многопоточному программированию. В курс вложена не только душа, но и знания, которые можно применить в любом языке, поскольку принципы многопоточного программирования везде одинаковы.
Курс преподаётся на языке Go, подробную информацию о нём можно посмотреть на сайте
▶️ Анонс курса на YouTube
Курс преподаётся на языке Go, подробную информацию о нём можно посмотреть на сайте
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥6❤5👍4⚡1
Как создавался курс?
В курс вложен весь мой личный опыт, связанный с многопоточным программированием. Помимо этого, во время создания курса я консультировался с ведущими разработчиками индустрии, например, общался с Романом Елизаровым — Ex Project Lead разработки языка Kotlin, человеком, который разрабатывал те самые корутины, также я учился многопоточному программированию у него в университете.
Подробную информацию о курсе можно посмотреть на сайте
В курс вложен весь мой личный опыт, связанный с многопоточным программированием. Помимо этого, во время создания курса я консультировался с ведущими разработчиками индустрии, например, общался с Романом Елизаровым — Ex Project Lead разработки языка Kotlin, человеком, который разрабатывал те самые корутины, также я учился многопоточному программированию у него в университете.
Подробную информацию о курсе можно посмотреть на сайте
1❤8🔥5👍4⚡1
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Version: Go 1.24.1
package main
func main() {
m := make(map[any]any)
insert(m, "IGOROUTINE COURSES")
insert(m, 1)
println(len(m))
}
func insert[T any](m map[any]any, a T) {
type Data struct{}
d := Data{}
m[d] = a
}
P.S. Подсвечено красным, ибо IDE старое
Please open Telegram to view this post
VIEW IN TELEGRAM
😱2
😱4
Что будет выведено в stdout?
С точки зрения стандарта языка:
Each type argument is substituted for its corresponding type parameter in the generic declaration. This substitution happens across the entire function or type declaration, including the type parameter list itself and any types in that list.
То есть, тип, объявленный внутри generic-функции insert[T], автоматически захватывает любой T, даже, если сам этот тип не использует T явно.
Таким образом, в будут ключи Data[string] и Data[int] и len(m) == 2.
https://go.dev/play/p/Nl250o6wX2X
Но всё немного тоньше. Если написать сигнатуру
, то итоговый ответ будет , но почему?
https://go.dev/play/p/EkkuBuwtQJ6
Потому что компилятор попытается вывести тип и ему подойдёт только , следовательно, в m будет всегда один ключ Data[any].
Two instantiated types are identical if they are instantiated from the same generic type and with the same full‑form type argument list.
В таких ситуациях нужно внимательно смотреть за выводом типов
🙄 🙄 Ещё больше примеров на курсах
Each type argument is substituted for its corresponding type parameter in the generic declaration. This substitution happens across the entire function or type declaration, including the type parameter list itself and any types in that list.
То есть, тип, объявленный внутри generic-функции insert[T], автоматически захватывает любой T, даже, если сам этот тип не использует T явно.
Таким образом, в
mНо всё немного тоньше. Если написать сигнатуру
func insert[T comparable](m map[any]T, a T)1Потому что компилятор попытается вывести тип
TanyTwo instantiated types are identical if they are instantiated from the same generic type and with the same full‑form type argument list.
В таких ситуациях нужно внимательно смотреть за выводом типов
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9
Кстати, курс The Nature Of Concurrency начинается совсем скоро, нас уже более 20 человек! Не упусти свой шанс стать мастером многопоточного программирования!
1❤7
Forwarded from Igor Panasyuk | IGORoutine Programming
Версия:
ARM64 Go compiler 1.24.2
package main
import (
"fmt"
)
type Key struct {
ID int
Callback func()
}
var globalMap = map[any]any{}
func main() {
callback := func() {
fmt.Println("@igoroutine")
}
key1 := Key{
ID: 1,
Callback: callback,
}
key2 := Key{
ID: 1,
Callback: callback,
}
insert[Key](key1)
insert[Key](key2)
fmt.Println(len(globalMap))
}
func insert[T any](key T) {
globalMap[key] = 27
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔4🔥3❤2
Forwarded from Igor Panasyuk | IGORoutine Programming
😱6❤2🔥2
Forwarded from Igor Panasyuk | IGORoutine Programming
Что будет выведено в stdout?
С точки зрения стандарта языка:
The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface (то есть any) type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
В текущем случае тип Key это произведение типов int и func. Поскольку в произведении типов присутствует тип func, то не имеет операторов сравнения и . Поэтому, согласно стандарту, получаем панику:
panic: runtime error: hash of unhashable type main.Key
https://go.dev/play/p/YgAgjKr6Jhp
The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface (то есть any) type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
В текущем случае тип Key это произведение типов int и func. Поскольку в произведении типов присутствует тип func, то
Key!===panic: runtime error: hash of unhashable type main.Key
go.dev
Go Playground - The Go Programming Language
1🔥7❤4✍1
Официальная позиция языка такая:
Goroutines do not have names; they are just anonymous workers. They expose no unique identifier, name, or data structure to the programmer. Some people are surprised by this, expecting the go statement to return some item that can be used to access and control the goroutine later.
The fundamental reason goroutines are anonymous is so that the full Go language is available when programming concurrent code. By contrast, the usage patterns that develop when threads and goroutines are named can restrict what a library using them can do.
Однако, иногда бывает нужно получить номер горутины, например, чтобы написать рекурсивный мьютекс, которого в Go нет, в отличие, например, от Java. Совсем недавно писали такой мьютекс на курсе.
Чтобы получить ID горутины, можно использовать stack trace
(Go Playground):
func Get() int64 {
var buf [64]byte
runtime.Stack(buf[:], false)
s := buf[len("goroutine "):]
s = s[:bytes.IndexByte(s, ' ')]
gid, _ := strconv.ParseInt(string(s), 10, 64)
return gid
}
Однако реализация через стектрейс довольно дорогая. Поэтому, более эффективно достать контекст горутины с помощью ассемблера, получив доступ к id:
// func getg() *g
TEXT ·getg(SB),NOSPLIT,$0-8
#ifdef GOARCH_386
MOVL (TLS), AX
MOVL AX, ret+0(FP)
#endif
#ifdef GOARCH_amd64
MOVQ (TLS), AX
MOVQ AX, ret+0(FP)
#endif
#ifdef GOARCH_arm
MOVW g, ret+0(FP)
#endif
#ifdef GOARCH_arm64
MOVD g, ret+0(FP)
#endif
#ifdef GOARCH_s390x
MOVD g, ret+0(FP)
#endif
RET
func Get() int64 {
return getg().goid
}
Более того, на гитхабе есть библиотека, которая поддерживает доступ к goroutineID для версий Go 1.3 и выше.
Важно понимать, что подобные решения не гарантируют обратную совместимость и их нужно использовать аккуратно.
Пишите в комментариях, какие темы осветить в будущих постах!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥6👍3
Во сколько раз многопоточная реализация сложения матриц 4096 x 1024, распараллеливающая вычисления по строкам на 10 ядрах, быстрее однопоточной реализации?
(90 % кода распараллелено)
(90 % кода распараллелено)
Anonymous Quiz
19%
В 3 раза
20%
В 5 раз
13%
В 7 раз
14%
В 9 раз
34%
В 10 раз
3😨6🔥2❤1
Мы все видели таких коллег
«Оо, я недавно изучил пакет unsafe и concurrency, сейчас распараллелю вычисления в этом запросе и уберу лишние копии».
В лучшем случае код становится менее читаемым.
В худшем — станет медленнее
Как однажды сказал Дональд Кнут — один из отцов информатики:
«Преждевременная оптимизация — корень всех зол»
Особенно наглядно это работает для CPU-bound задач — например, сложение матриц, хэширование, кодирование. Интуитивно кажется, что «больше горутин = быстрее», но это ловушка.
Закон Амдала отлично иллюстрирует, насколько сложно получить ускорение в этом случае. Например, при 60% параллельного кода разницы между 100 и 1000 ядрами практически нет
С точки зрения практики, всегда лучше сделать бенчмарк. Как видим, ответ почти сошёлся.
BenchmarkAdd/par/w=1-12 168
BenchmarkAdd/par/w=10-12 776
При этом важно понимать, что с IO-bound задачами всё иначе — там другие принципы и прирост может быть на порядки выше.
Кстати, как раз сегодня на канале вышло видео про устройство атомиков и распараллеливание CPU-bound задач.
Если же хочется разобраться в этих принципах глубже, 25 ноября стартует 2 поток курса The Nature of Concurrency. Это системное погружение в базу многопоточности: от устройства атомиков, мьютексов до модели памяти, устройства race detector'a и lock-free алгоритмов.
Курс закрывает 100% вопросов про Concurrency на собеседованиях, видеоотзывы можно посмотреть на сайте. В честь распродажи 11.11 до конца недели действует скидка на PREMIUM тариф, на нём есть возможность поработать со мной 1 на 1, осталось всего 2 места.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
4❤5🔥3💯1
Всё началось ещё давно, когда морякам необходимо было знать точное время, чтобы определить точное местоположение корабля в океане. Это связано с принципом долготы — одной из двух координат на Земле. В 1731 году изобрели хронометр, который надолго стал золотым стандартом на море. В современном мире используют спутниковые системы (GPS).
Но как же наши компьютеры понимают, сколько сейчас время? В каждом компьютере есть маленький чип — Real-Time Clock (RTC). Он работает даже тогда, когда устройство выключено. Но есть проблема в том, что RTC не очень точный, за минуту дрейф может составлять миллисекунды, а за дни и недели — уже секунды и больше.
Для решения этой проблемы был придуман Network Time Protocol (NTP). Операционная система почти всегда периодически синхронизирует время через интернет. Но откуда те, с кем мы синхронизируемся, знают точное время, как они его считают?
Существует международное атомное время (TAI - International Atomic Time). Оно равняется средневзвешенному времени цезиевых часов из разных лабораторий, с поправками на локальную разницу гравитации. Через GPS атомные часы калибруются по отдельности через положение GPS-спутников. Сами атомные часы завязаны на факт, что одна секунда равна времени, за которое атом цезия-133 совершает 9_192_631_770 переходов между энергетическими состояниями, там всё неочевидно, оставим эти вопросы физикам)
Но где же здесь всем знакомый UTC (Coordinated Universal Time)? На самом деле UTC — это шкала, которая идёт почти как TAI, но периодически в неё вставляют високосные секунды, чтобы не убегать от астрономического времени. Поскольку Земля со временем вращается медленнее, «солнечные сутки» постепенно расходятся с атомным временем. Поэтому международная служба времени
23:59:60 <- вставленная секунда
Так делали 27 раз, начиная с 1972 года. Високосная секунда кажется мелочью — всего одна лишняя секунда. Но на практике 30 июня 2012 года она вызвала крупные сбои по всему миру: в интернете, авиакомпаниях, дата-центрах, базах данных, Linux-серверах и даже в платежных системах. В частности, в ядре Linux был баг в обработке таймеров, и при вставке секунды некоторые таймеры начинали бесконечно перезапускаться, загружая CPU на 100%.
Эта секунда так всех достала, что в ноябре 2022 года на 27-й Генеральной конференции по мерам и весам было принято решение отказаться от дополнительных секунд к 2035 году или ранее))
Но как всё-таки получать точное время? Ведь даже при использовании NTP нет жёсткой гарантии на дрейф, ибо всё зависит от множества факторов (аппаратные часы, сеть, серверы) В нормальных условиях речь обычно идёт о миллисекундах, иногда десятках миллисекунд, но это всё равно слишком много, чтобы на это завязаться.
В рамках одного процесса ОС эту проблему решают монотонными часами. Например, в Go пакет time хранит такое время от операционной системы. В отличие от "реального" времени оно монотонно, то есть можно более безопасно реализовать различные таймеры.
Но что делать, если нам нужно точное время между разными компьютерами? Например, базам данных критично получать точное время для выбора меток при реализации распределённых транзакций с уровнем изоляции snapshot isolation (MVCC).
Эту проблему решают специальными чипами с атомными часами, например, Chip-Scale Atomic Clock (CSAC), который можно купить за +- 5.000$. Далее такую аппаратную поддержку используют в time server'ах, с помощью которых приложение может получить "интервал доверия" для текущего времени — диапазон, в котором оно почти наверняка находится. Сами серверы бывают разные (master, slave), соответственно, с разной точностью.
Подводя итоги, можно сказать одно. Прежде чем сильно завязаться на время в вашей системе, подумайте несколько раз, правда ли вы этого хотите
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
3😱7 4 4❤3