🎬 Как ИИ ускоряет разработку и где ломаются архитектуры
Мы провели открытый вебинар, где разобрали реальные боли проектирования автономных систем. Ольга Лукьянова на практическом кейсе показала, как использовать ИИ-ассистентов для реальных задач. Вы просили запись встречи — она уже в открытом доступе!
Что внутри:
— Как с помощью ИИ быстрее разбираться в незнакомом коде и готовить пулл-реквесты;
— Критерии выбора между одним агентом и мультиагентной системой;
— Разбор популярных архитектурных ошибок и ограничений современных ИИ;
— Практические рекомендации по проектированию и внедрению облачных агентов.
👉 Посмотреть полную запись можно тут:
● VK
● YouTube
🚀 Хотите пойти дальше открытого вебинара? Если вы готовы перейти от простых промптов к проектированию надежных, отказоустойчивых ИИ-систем, которые не сливают бюджет компании на API, приходите на курс AgentOps. Поток уже стартовал, но двери еще приоткрыты!
👉 Успеть на курс AgentOps
Мы провели открытый вебинар, где разобрали реальные боли проектирования автономных систем. Ольга Лукьянова на практическом кейсе показала, как использовать ИИ-ассистентов для реальных задач. Вы просили запись встречи — она уже в открытом доступе!
Что внутри:
— Как с помощью ИИ быстрее разбираться в незнакомом коде и готовить пулл-реквесты;
— Критерии выбора между одним агентом и мультиагентной системой;
— Разбор популярных архитектурных ошибок и ограничений современных ИИ;
— Практические рекомендации по проектированию и внедрению облачных агентов.
👉 Посмотреть полную запись можно тут:
● VK
● YouTube
🚀 Хотите пойти дальше открытого вебинара? Если вы готовы перейти от простых промптов к проектированию надежных, отказоустойчивых ИИ-систем, которые не сливают бюджет компании на API, приходите на курс AgentOps. Поток уже стартовал, но двери еще приоткрыты!
👉 Успеть на курс AgentOps
❤2
http.ListenAndServe(":8080", nil) считается плохой практикойnil означает DefaultServeMux, глобальный роутер. В него может зарегистрировать хендлер любой импортированный пакет, например net/http/pprof делает это в init. Так наружу случайно утекают отладочные ручки. У такого сервера нет тайм аутов. Правильнее создать свой
Server и свой ServeMux.Правильный вариант:
srv := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
log.Fatal(srv.ListenAndServe())Please open Telegram to view this post
VIEW IN TELEGRAM
Это про автоматические исправления кода — фиксеры (например,
go fix, gofmt, suggested fixes из go vet / analysis-фреймворка, или --fix в линтерах вроде golangci-lint). Гарантия говорит, что такой фикс меняет только форму кода, но не его поведение во время выполнения.Под поведением тут понимается наблюдаемая семантика: что программа возвращает, какие у неё сайд-эффекты — запись в файл, вызовы по сети, вывод, — как идёт control flow, какие ошибки и паники она порождает. То есть на тех же входных данных до и после фикса программа должна давать тот же результат и те же эффекты. Трансформация behavior-preserving, семантически нейтральная.
Пример: фиксер может переписать устаревший API на новый, переставить импорты через
goimports, отформатировать код — но не должен, скажем, изменить условие в if так, что поменяется ветвление.И тут ключевой момент — формулировка «should not», а не «will not». Это заявленное свойство по дизайну, а не строгая гарантия на все случаи. В Go, где есть интерфейсы, рефлексия, горутины и гонки, всегда найдётся пограничный кейс, где формально эквивалентная замена всё же меняет смысл. Поэтому на практике фиксы обычно делят на safe и unsafe: safe можно катить массово, unsafe применяют осознанно.
Please open Telegram to view this post
VIEW IN TELEGRAM
http.Client на каждый запросНет.
Client и его Transport безопасны для конкурентного использования и держат пул TCP соединений. Новый клиент на каждый запрос убивает keep alive, каждый вызов будет заново устанавливать соединение вместе с TLS рукопожатием. Правильно создать один клиент на приложение и задать ему тайм аут, потому что у
http.DefaultClient его нет.Please open Telegram to view this post
VIEW IN TELEGRAM
💰 Почему одним Data Scientist платят больше, чем другим?
Дело не только в знании Python и ML-библиотек. Во многих компаниях уровень специалиста оценивают по математической подготовке: теории вероятностей, статистике, линейной алгебре и математическому анализу.
Именно эти знания помогают понимать модели, решать более сложные задачи и претендовать на позиции с более высокой оплатой.
На курсе «Математика для Data Science» вы изучите разделы, которые используются в работе Data Scientist и ML Engineer.
Что вас ждёт:
🔹 40+ видеолекций и 150+ практических заданий на Python
🔹 Проверка домашних работ и обратная связь от преподавателей
🔹 Подготовка к техническим собеседованиям
🔹 Программа от преподавателей ВМК МГУ, НИУ ВШЭ и экспертов индустрии
👉 Записаться на бесплатный демо-урок
Дело не только в знании Python и ML-библиотек. Во многих компаниях уровень специалиста оценивают по математической подготовке: теории вероятностей, статистике, линейной алгебре и математическому анализу.
Именно эти знания помогают понимать модели, решать более сложные задачи и претендовать на позиции с более высокой оплатой.
На курсе «Математика для Data Science» вы изучите разделы, которые используются в работе Data Scientist и ML Engineer.
Что вас ждёт:
🔹 40+ видеолекций и 150+ практических заданий на Python
🔹 Проверка домашних работ и обратная связь от преподавателей
🔹 Подготовка к техническим собеседованиям
🔹 Программа от преподавателей ВМК МГУ, НИУ ВШЭ и экспертов индустрии
👉 Записаться на бесплатный демо-урок
bigSlice = bigSlice[:5]Нет, не обязательно. Операция
[:5] создаёт новый слайс-заголовок с длиной 5, но он по-прежнему указывает на тот же самый underlying array. Пока хотя бы один слайс ссылается на этот массив, сборщик мусора не может его освободить. То есть даже если нам нужны первые 5 байт, за спиной может «висеть» все 10 MB:Дело в том, что срез — это лишь тройка из указателя на массив, длины и ёмкости. Урезание длины меняет только заголовок и никак не влияет на память под ним. Capacity нового слайса по-прежнему указывает на конец исходного массива, поэтому GC считает его достижимым.
Чтобы отдать большой массив сборщику, нужные данные копируют в новый, компактный слайс, а ссылку на исходный обнуляют:
smallCopy := make([]byte, len(smallSlice))
copy(smallCopy, smallSlice)
bigSlice = nil
Тот же эффект короче — через
append в nil-слайс, который выделит свежий массив под реальный объём данных:smallCopy := append([]byte(nil), smallSlice...)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Media is too big
VIEW IN TELEGRAM
📹 Из чего на самом деле состоит ИИ-агент?
Прикрепили для вас свежую вырезку из вебинара. Внутри, что прячется под капотом агентных систем: от LLM-ядра до вызова внешних инструментов. Обсуждаем, какими бывают агенты (спойлер: далеко не только автономными) и когда какой подход использовать.
Готовы перейти от видео к практике и собрать свой первый продакшн-кейс?
Прямо сейчас у нас действует акция «3 курса по цене 1»:
Сомневаетесь, подойдет ли вам формат? Оставьте заявку и пройдите бесплатный демо-урок, чтобы протестировать платформу перед покупкой.
👉 Пройти демо-урок и забрать 3 курса по цене 1
Прикрепили для вас свежую вырезку из вебинара. Внутри, что прячется под капотом агентных систем: от LLM-ядра до вызова внешних инструментов. Обсуждаем, какими бывают агенты (спойлер: далеко не только автономными) и когда какой подход использовать.
Готовы перейти от видео к практике и собрать свой первый продакшн-кейс?
Прямо сейчас у нас действует акция «3 курса по цене 1»:
🔹 При покупке VIP-тарифа нового потока «Разработка ИИ-агентов» вы получаете в подарок хардкорный курс «AgentOps» + ещё один любой курс Академии на ваш выбор!
🔹 Ваша чистая экономия — 129 000 ₽! Два топовых курса по созданию и контролю агентов обойдутся вам всего в 134 000 ₽ вместо 263 000 ₽. Плюс третий курс бонусом (например, «Математика для AI»).
Сомневаетесь, подойдет ли вам формат? Оставьте заявку и пройдите бесплатный демо-урок, чтобы протестировать платформу перед покупкой.
👉 Пройти демо-урок и забрать 3 курса по цене 1
Через второй возвращаемый параметр при обращении к мапе — так называемый comma-ok. Обычное чтение
v := m[key] всегда вернёт значение: если ключа нет, это будет нулевое значение типа (0 для чисел, "" для строк, nil для указателей). А значит, по одному только
v нельзя понять, лежал ли там реальный ноль или ключа просто не было:m := map[string]int{"a": 0}
v := m["a"] // 0 — но ключ есть
v = m["b"] // 0 — а ключа нетФорма с двумя переменными решает это: второе значение — булев флаг, который равен
true, только если ключ действительно присутствует в мапе. Именно на него и нужно смотреть, а не на само значение:v, ok := m["a"]
if ok {
// ключ есть, v — реальное значение (даже если это 0)
}
_, ok = m["b"] // ok == false, ключа нет
Отсюда типичный идиоматичный паттерн — проверка и использование в одном
if:if v, ok := m[key]; ok {
// работаем с v
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Обычное
v := <-ch из закрытого канала не заблокируется и не паникует, а сразу вернёт нулевое значение типа. Поэтому по одному
v нельзя отличить «пришёл реальный ноль» от «канал закрыт и пуст — ровно как с мапой:v := <-ch // 0 — но это может быть и настоящее значение, и признак закрытия
Второй параметр решает вопрос: флаг
ok равен true, пока из канала можно прочитать отправленное значение, и становится false, когда канал закрыт и в нём не осталось буферизованных данных. Важно, что закрытый канал сначала отдаёт всё, что в него успели записать, и только потом начинает возвращать
false:v, ok := <-ch
if !ok {
// канал закрыт и пуст
}
На практике за приёмом из канала обычно стоит
range, который сам корректно завершается при закрытии — отдельная проверка ok не нужна:for v := range ch {
// выполняется, пока канал не закрыт и не пустой
}Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤔2
🔥 Как перестать слепо доверять ИИ и начать им управлять?
1–2 августа на «ИИ-выходных» вы научитесь проектировать архитектуру автономных AI-агентов и контролировать их работу.
Что будет в вашем портфолио после обучения:
— Вы выйдете с готовым профилем AI-инженера (отлично дополнит ваши LinkedIn и GitHub).
— Освоите связку Python, FastAPI, OpenAI API, Docker и PostgreSQL.
— Соберете полноценный AI-сервис под вашу личную задачу.
Для кого: junior-middle разработчики. Вы пишете на Python, работаете с Git и терминалом (с нуля не подойдет, темп очень быстрый!).
👨💻 Спикер: Алексей Жиряков (Сбер, GenAI).
Места строго ограничены!
👉 Изучить программу и занять место
1–2 августа на «ИИ-выходных» вы научитесь проектировать архитектуру автономных AI-агентов и контролировать их работу.
Что будет в вашем портфолио после обучения:
— Вы выйдете с готовым профилем AI-инженера (отлично дополнит ваши LinkedIn и GitHub).
— Освоите связку Python, FastAPI, OpenAI API, Docker и PostgreSQL.
— Соберете полноценный AI-сервис под вашу личную задачу.
Для кого: junior-middle разработчики. Вы пишете на Python, работаете с Git и терминалом (с нуля не подойдет, темп очень быстрый!).
👨💻 Спикер: Алексей Жиряков (Сбер, GenAI).
Места строго ограничены!
👉 Изучить программу и занять место
Функция
len(ch) возвращает количество элементов, которые сейчас лежат в буфере канала. Функция cap(ch) возвращает вместимость буфера, то есть сколько элементов канал может хранить, не блокируя отправителя.Пример с буферизированным каналом:
ch := make(chan int, 5)
ch <- 1
ch <- 2
fmt.Println(len(ch)) // 2
fmt.Println(cap(ch)) // 5
Для небуферизированного канала обе функции всегда дают ноль, потому что у него нет буфера, где данные могли бы задержаться.
ch := make(chan int)
fmt.Println(len(ch)) // 0
fmt.Println(cap(ch)) // 0
Значение
len(ch) это снимок состояния на конкретный момент. Пока вы читаете результат и что-то с ним делаете, другая горутина уже могла записать или забрать элемент.Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
Строка в Go это неизменяемый срез байт. Поэтому подстрока берётся так же, как срез, но с одной оговоркой. Индексы считаются в байтах, а не в символах. На ASCII разницы не видно, на кириллице или эмодзи всё ломается.
Срез по байтам
s := "hello world"
fmt.Println(s[0:5]) // hello
fmt.Println(s[6:]) // world
Такой срез не копирует данные, он ссылается на тот же массив байт. Работает за O(1).
Теперь то же самое с кириллицей:
s := "привет"
fmt.Println(s[0:3]) // "пр"? нет, это "п" с хвостом
Каждая кириллическая буква в UTF-8 занимает два байта, так что
s[0:3] разрежет символ пополам и вы получите битые данные.Срез по символам
Если нужны именно символы, переводим строку в срез рун:
r := []rune("привет")
fmt.Println(string(r[0:3])) // приЗдесь уже есть аллокация и проход по всей строке, то есть O(n). Для длинных строк в горячем цикле это заметно.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
🤨 Как заставить AI-агента не ломать архитектуру, а нормально писать код?
Мы привыкли общаться с ИИ промптами, но для автономных систем это путь к бесконечным циклам и сливу бюджета. Чтобы убрать хаос, инженеры переходят на Spec-Driven Development (SDD).
Вот как этот подход меняет работу агента на практике:
🔹Контракт вместо текста. Сначала пишется строгая спецификация (JSON-схема/OpenAPI) и автотесты. Агент зажат в рамки интерфейсов, за которые физически не может выйти.
🔹Контроль на шагах. Внутри петли Think-Act-Observe агент сверяет действия со спецификацией.
🔹Саморефлексия. Если ИИ нарушил типы или «додумал» лишнее, тест падает. Агент получает ошибку в контекст и сам правит код, не выходя за рамки ТЗ.
Это лишь база того, как укротить ИИ-разработку. Если вы хотите глубоко внедрить эту методологию, научиться проектировать архитектурные контракты и собирать отказоустойчивые системы —оставляйте заявку на наш новый курс по Spec-Driven Development. Стартуем совсем скоро🙂
Мы привыкли общаться с ИИ промптами, но для автономных систем это путь к бесконечным циклам и сливу бюджета. Чтобы убрать хаос, инженеры переходят на Spec-Driven Development (SDD).
Вот как этот подход меняет работу агента на практике:
🔹Контракт вместо текста. Сначала пишется строгая спецификация (JSON-схема/OpenAPI) и автотесты. Агент зажат в рамки интерфейсов, за которые физически не может выйти.
🔹Контроль на шагах. Внутри петли Think-Act-Observe агент сверяет действия со спецификацией.
🔹Саморефлексия. Если ИИ нарушил типы или «додумал» лишнее, тест падает. Агент получает ошибку в контекст и сам правит код, не выходя за рамки ТЗ.
Это лишь база того, как укротить ИИ-разработку. Если вы хотите глубоко внедрить эту методологию, научиться проектировать архитектурные контракты и собирать отказоустойчивые системы —оставляйте заявку на наш новый курс по Spec-Driven Development. Стартуем совсем скоро🙂
❤1😁1😢1
Задача звучит просто, но у неё три разных ответа. Нужно узнать, есть ли подстрока вообще. Нужно узнать, где она находится. Нужно достать то, что вокруг неё. Для каждого случая в пакете
strings есть своя функция, и брать не ту это лишняя работа.Просто проверить наличие
if strings.Contains(s, "error") {
// подстрока есть
}
strings.Contains возвращает bool. Рядом живут strings.HasPrefix и strings.HasSuffix для начала и конца строки, они дешевле, потому что не сканируют всё подряд.if strings.HasPrefix(path, "/api/") {
...
}Ещё есть
strings.ContainsAny, которая проверяет вхождение любого символа из набора, и strings.ContainsRune для одной руны.Найти позицию
i := strings.Index(s, "role=")
if i == -1 {
return errors.New("not found")
}
strings.Index возвращает байтовый индекс первого вхождения либо -1. Проверка на -1 обязательна, иначе получите панику при попытке сделать срез. strings.LastIndex ищет с конца. strings.IndexByte работает с одним байтом и заметно быстрее, если ищете, например, запятую.Индекс байтовый, но подставлять его в срез безопасно. Совпадение подстроки всегда начинается на границе символа, потому что UTF-8 самосинхронизирующаяся кодировка.
Достать содержимое
Чаще всего индекс нужен не сам по себе, а чтобы отрезать кусок. Тогда
strings.Cut короче и понятнее.before, after, found := strings.Cut("key=value", "=")
if !found {
return errors.New("bad format")
}
// before "key", after "value"Это идиоматичный способ с Go 1.18. Он заменяет связку
Index плюс два среза и не даёт ошибиться со смещением на длину разделителя.Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
🚀 Уже завтра стартует новый поток курса «ИИ-агенты»!
Мы собрали мощнейший состав преподавателей. Учить вас проектировать архитектуру и собирать продакшн-агентов будут инженеры и исследователи из топовых IT-компаний.
Старт уже завтра!
Сомневаетесь, подойдет ли вам программа и подача? Начните с бесплатного демо-урока!
Всего за 2 часа вы заглянете под капот ИИ-агента, поймете, чем мышление модели отличается от ее ответа, и научите систему чинить собственный код. Это идеальный способ протестировать нашу платформу перед покупкой.
🔗 Пройти демо-урок и занять место на курсе
Мы собрали мощнейший состав преподавателей. Учить вас проектировать архитектуру и собирать продакшн-агентов будут инженеры и исследователи из топовых IT-компаний.
Старт уже завтра!
Сомневаетесь, подойдет ли вам программа и подача? Начните с бесплатного демо-урока!
Всего за 2 часа вы заглянете под капот ИИ-агента, поймете, чем мышление модели отличается от ее ответа, и научите систему чинить собственный код. Это идеальный способ протестировать нашу платформу перед покупкой.
🔗 Пройти демо-урок и занять место на курсе
🔥 Стартуем СЕГОДНЯ! Новый поток курса «Разработка ИИ-агентов» открыт
По этому поводу мы решили выложить закрытую запись одного из уроков из программы. Найти её в поиске YouTube нельзя — она доступна только по ссылке и всем, кто будет на курсе.
Внутри глубокий разбор LLM от Алексея Яндутова (Senior ML-инженер, развивал ответы «Алисы» и «Нейро» в Яндексе). Учимся получать точный результат без галлюцинаций.
Что внутри урока:
После просмотра вы поймете, когда хватает промпт-инжиниринга, а когда нужен RAG или fine-tuning.
👉Смотреть закрытый урок на YouTube
Понравился урок? Переходите на новый уровень! Оставляйте заявку на курс, чтобы научиться проектировать надежные автономные системы. Обучение началось, но вы еще успеваете присоединиться.
🔗 Занять место на курсе
По этому поводу мы решили выложить закрытую запись одного из уроков из программы. Найти её в поиске YouTube нельзя — она доступна только по ссылке и всем, кто будет на курсе.
Внутри глубокий разбор LLM от Алексея Яндутова (Senior ML-инженер, развивал ответы «Алисы» и «Нейро» в Яндексе). Учимся получать точный результат без галлюцинаций.
Что внутри урока:
- Устройство LLM.
- Рабочие шаблоны промптов (Persona, Chain-of-Thought и др.).
- Разбор реального кейса Яндекса. Как автоматизировать разметку, обойти качество людей на 5% и срезать косты на 60%.
После просмотра вы поймете, когда хватает промпт-инжиниринга, а когда нужен RAG или fine-tuning.
👉Смотреть закрытый урок на YouTube
Понравился урок? Переходите на новый уровень! Оставляйте заявку на курс, чтобы научиться проектировать надежные автономные системы. Обучение началось, но вы еще успеваете присоединиться.
🔗 Занять место на курсе
❤1
Мы никогда не склеиваем запрос строкой. Всегда плейсхолдеры драйвера, значения уходят отдельно от текста запроса:
row := db.QueryRowContext(ctx, "SELECT id FROM users WHERE email = $1", email)
Имена таблиц и колонок так подставить нельзя, для них белый список допустимых значений:
var allowed = map[string]string{"created": "created_at", "email": "email"}
col, ok := allowed[r.URL.Query().Get("sort")]
if !ok {
col = "created_at"
}
query := fmt.Sprintf("SELECT id FROM users ORDER BY %s DESC", col)Дополнительно ограниченные права у пользователя базы, чтобы ошибка не стоила всей схемы.
XSS
Пользовательский текст не попадает в HTML напрямую. Рендерим через
html/template, он экранирует с учётом контекста, то есть по разному внутри тега, атрибута, href и блока <script>. text/template не экранирует ничего, в веб хендлере его быть не должно.Приводить ввод к
template.HTML нельзя, это отключение защиты. Если пользователю нужна разметка, чистим санитайзером вроде bluemonday по белому списку тегов.Для API хватает
encoding/json, но заголовки обязательны, иначе браузер угадает тип и отрендерит ответ как страницу:w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")Сверху
Content-Security-Policy и куки с HttpOnly, чтобы случайная дыра не привела к краже сессии.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
🔥 Курс «Разработка ИИ-агентов» стартовал, но вы еще успеваете присоединиться!
Мы только начали, а первый практический воркшоп пройдет только 23 июля. До этого времени вы спокойно успеете изучить материалы и нагнать группу.
💼 Главная фишка: финальный проект в портфолио:
🎁 Упомяните менеджеру специальное предложение «3 курса по цене 1»: Берете VIP-тариф — получаете курс «Разработка ИИ-агентов», хардкорный «AgentOps» и ещё один курс на выбор. Выгода 129.000 ₽!
Двери потока вот-вот закроются окончательно. Успейте забрать стек курсов и начать работу над реальным проектом
🔗 Занять место и забрать 3 курса
Мы только начали, а первый практический воркшоп пройдет только 23 июля. До этого времени вы спокойно успеете изучить материалы и нагнать группу.
💼 Главная фишка: финальный проект в портфолио:
В финальном проекте вы сможете выбрать один из двух вариантов: реализовать свою идею или решить задачу от партнера курса — крупной российской финтех-компании. Вы будете работать с датасетом, построенным по реальным сценариям, получите бизнес-контекст и продовые ограничения. В результате соберете AI-агента, который станет сильным проектом для портфолио.
🎁 Упомяните менеджеру специальное предложение «3 курса по цене 1»: Берете VIP-тариф — получаете курс «Разработка ИИ-агентов», хардкорный «AgentOps» и ещё один курс на выбор. Выгода 129.000 ₽!
Двери потока вот-вот закроются окончательно. Успейте забрать стек курсов и начать работу над реальным проектом
🔗 Занять место и забрать 3 курса
😢1
Базовая конструкция — один канал
jobs как очередь и N воркеров, которые из него читают. Канал сам работает балансировщиком: свободный воркер забирает следующую задачу, вручную раздавать ничего не нужно. Для управления жизненным циклом добавляем context (отмена, таймаут, shutdown), sync.WaitGroup (дождаться завершения всех) и правило «кто пишет в канал, тот его и закрывает» — results закрываем только после wg.Wait(), иначе паника. Закрытие jobs — сигнал воркерам, что задачи кончились.Сколько горутин — зависит от природы задачи. Для CPU-bound (вычисления, парсинг) смысла запускать больше горутин, чем ядер, нет: они будут драться за те же ядра и добавлять оверхед на переключение контекста. Ориентир —
runtime.GOMAXPROCS(0). Для IO-bound (БД, HTTP, диск) горутина большую часть времени спит в ожидании ответа, поэтому воркеров имеет смысл сильно больше ядер — десятки, сотни. Но потолок здесь задаёт не CPU, а узкое место вниз по потоку: пул коннектов к БД, rate limit API, лимит дескрипторов. Запускать 500 воркеров при 20 коннектах к базе бессмысленно.Грубая прикидка через закон Литтла:
N ≈ ядра × (1 + время_ожидания / время_CPU). Плюс не забываем про память — горутина дешёвая (~2–8 КБ стека), но при сотнях тысяч воркеров плюс их буферы это уже гигабайты.Правильный инженерный ответ: точное число не угадывается, а подбирается. Берём разумный старт (
GOMAXPROCS для CPU, кратно больше для IO), вешаем метрики (p99-латентность, throughput, глубина очереди, загрузка CPU) и тюним под реальную нагрузку. Число воркеров — это параметр конфигурации, а не константа в коде. И отдельно важен backpressure: если продьюсер быстрее пула, нужно заранее решить — копить в буфере, блокировать продьюсера или дропать задачи, иначе очередь растёт до OOM.Please open Telegram to view this post
VIEW IN TELEGRAM
1👍4❤3
Forwarded from Proglib.academy | IT-курсы
Самое интересное, что разница здесь не столько в модели
На живом демо покажем, как один и тот же запрос работает без агентной системы и с ней
Please open Telegram to view this post
VIEW IN TELEGRAM
Сначала уточнение, за которое дают плюс на собесе: важно понять, что именно ограничиваем.
Concurrency limit — сколько запросов летит одновременно (не больше 10 в моменте). Примитив — семафор.
Rate limit — сколько запросов в единицу времени (100 rps). Примитив — token bucket, x/time/rate.
Их часто путают. «Не больше 10 параллельных» — первое. «Не больше 100 в секунду» — второе. Дальше про concurrency.
Хороший выбор — семафор. В Go проще всего сделать его на буферизированном канале: канал ёмкости N — это счётчик свободных слотов:
sem := make(chan struct{}, 10)
for _, req := range requests {
sem <- struct{}{} // заняли слот
go func(r Request) {
defer func() { <-sem }() // освободили
callExternalAPI(r)
}(req)
}struct{} — потому что нужен только факт занятости, он весит 0 байт. Канал даёт и счётчик, и блокировку сразу.На практике берут
errgroup.SetLimit — тот же семафор, но с ошибками, Wait и отменой контекста из коробки:g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10)
for _, req := range requests {
req := req
g.Go(func() error {
return callExternalAPI(ctx, req)
})
}
return g.Wait()
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11