Код на салфетке
2.22K subscribers
746 photos
14 videos
2 files
788 links
Канал для тех, кому интересно программирование на Python и не только.

Сайт: https://pressanybutton.ru/
Чат: https://t.iss.one/+Li2vbxfWo0Q4ZDk6
Заметки автора: @writeanynotes

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥9
Разберём вчерашнюю задачу на асинхронное программирование, где нужно запрашивать данные с нескольких API, логируя как успешные, так и неудачные запросы с таймаутами.

Задача:
Вы пишете асинхронную программу для запросов к API с таймаутами. Вам нужно, чтобы программа продолжала работу даже при возникновении таймаутов. Коллега предложил добавить логирование успешных запросов. Посмотрите на код, как думаете, что он выведет?

Код задачи:
import asyncio

async def fetch_data(api_name, delay):
await asyncio.sleep(delay)
if delay > 1:
raise asyncio.TimeoutError(f"Timeout for {api_name}")
return api_name

async def log_api_calls():
apis = [("API_1", 0.5), ("API_2", 1.5), ("API_3", 0.3)]
tasks = [fetch_data(api, delay) for api, delay in apis]

for task in asyncio.as_completed(tasks):
try:
api_name = await task
print(f"Logged: {api_name} success")
except asyncio.TimeoutError as e:
print(f"Logged error: {str(e)}")

asyncio.run(log_api_calls())


Разбор задачи:
1. Основная логика работы функции `fetch_data`:
- Эта асинхронная функция принимает два аргумента: api_name (название API) и delay (задержка перед выполнением).
- Функция "спит" указанное количество секунд с помощью await asyncio.sleep(delay).
- Если задержка больше 1 секунды, вызывается исключение asyncio.TimeoutError с сообщением о таймауте для конкретного API.
- Если задержка меньше или равна 1, функция возвращает название API.

2. Асинхронная обработка в `log_api_calls`:
- Мы создаём список API с задержками: apis = [("API_1", 0.5), ("API_2", 1.5), ("API_3", 0.3)].
- Для каждого API создаётся задача (task) вызова функции fetch_data. Эти задачи запускаются "параллельно" благодаря конструкции tasks = [fetch_data(api, delay) for api, delay in apis].
- Далее цикл asyncio.as_completed(tasks) перебирает задачи по мере их завершения. Это полезно для того, чтобы мы могли обрабатывать результаты задач в том порядке, в котором они завершились, а не в том, в котором они были созданы.

3. Логирование успешных запросов и ошибок:
- В цикле мы ожидаем завершения каждой задачи с помощью await task. Если задача успешно завершена, выводится сообщение: Logged: {api_name} success.
- Если задача завершается исключением asyncio.TimeoutError, мы перехватываем его и выводим сообщение об ошибке.

Что выведет программа:
1. API_1 с задержкой 0.5 секунд завершится успешно:
- Logged: API_1 success.

2. API_2 с задержкой 1.5 секунд вызовет таймаут:
- Logged error: Timeout for API_2.

3. API_3 с задержкой 0.3 секунды завершится успешно:
- Logged: API_3 success.

Итоговый вывод:
Logged: API_3 success
Logged error: Timeout for API_2
Logged: API_1 success


Пояснение:
Так как asyncio.as_completed(tasks) возвращает задачи по мере их завершения, порядок вывода не соответствует порядку запуска запросов. Мы видим, что сначала завершился запрос с минимальной задержкой (API_3), потом произошёл таймаут для API_2, а завершение API_1 произошло последним, так как его задержка чуть больше, чем у API_3, но меньше, чем у API_2.

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


P.S. На прошлой неделе было много всего и разбора не было, выложу его на неделе, если он нужен, т.к. позапрошлая задача действительно очень простая.
🔥5👍2
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥7
Привет, друзья!

Прошла еще одна неделя, и у нас накопилось много интересных материалов: статьи, новости и полезные советы. Вот наш недельный дайджест:

Понедельник (30.09.2024) Дайджест за предыдущую неделю

Вторник (01.10.2024) Знаете ли вы, как глобальная блокировка интерпретатора (GIL) влияет на многопоточность в Python?

Среда (02.10.2024)

Четверг (03.10.2024) Вхожу в IT - telegram bot (часть 1)

Пятница (04.10.2024) Пятничный кинорелакс

Суббота (05.10.2024) Задача и Приглашение на контест по разработке микросервиса

Воскресенье (06.10.2024) Текстовый разбор задачи


Спасибо, что остаетесь с нами! Надеемся, что эти материалы будут вам полезны. Удачи в новой неделе!

С уважением,
Команда канала "Код на салфетке".

#дайджест #материалы #новости #код_на_салфетке
🔥7👍3
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥4
Знаете ли вы, как Namespace и cgroups обеспечивают изоляцию в контейнеризации?

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

Cgroups (control groups) управляют распределением системных ресурсов между контейнерами, такими как процессорное время, память, дисковая I/O и сетевые ресурсы. С помощью cgroups можно задавать лимиты на использование ресурсов, обеспечивая справедливое распределение и предотвращая чрезмерное потребление ресурсов одним контейнером. Вместе Namespace и cgroups обеспечивают надежную и эффективную изоляцию, позволяя контейнеризированным приложениям работать независимо и безопасно в масштабируемых средах.

Код на салфетке x Кусочки кода
🔥6
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥3
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥2
Obsidian LiveSync - совместная работа над проектной документацией
Автор: Иван Ашихмин

Obsidian может быть не только редактором заметок, но и средой для ведения проектной документации всей командой. О том, как настроить синхронизацию между устройствами написано в этом посте.


Читать пост в Telegram

Пост на сайте
Поддержать проект на Boosty
Поддержать проект в Telegram

#Гайды #Полезные_инструменты #Obsidian #LiveSync #плагины_Obsidian #Синхронизация_заметок
🔥7❤‍🔥1👌1
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥3
Привет, друзья!

Снова пятница, а это значит, что настало время для нашего традиционного кинопоста!

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

Фильм: Переводчик

Год: 2023

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

Приятного просмотра!
🔥8💩21🌚1
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥3
Что выведет этот код? №41

Задача:

У вас есть асинхронное приложение, которое запускает программу и одновременно читает текстовые файлы с диска. Программа должна использовать текст, который подгружается при старте. Две задачи запускаются параллельно: одна читает текстовые файлы, другая — запускает программу, которая использует этот текст.

Посмотрите на код ниже и определите, что будет выведено:
🔥3
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥2🤔1
Вчера мы опубликовали задачу, в которой асинхронное приложение одновременно выполняет две задачи: читает текстовые файлы и запускает программу, использующую этот текст. Однако, несмотря на параллельное выполнение задач, возникает проблема с тем, что текст может быть недоступен в момент его обработки.

Задача:
У вас есть асинхронное приложение, которое запускает программу и одновременно читает текстовые файлы с диска. Программа должна использовать текст, который подгружается при старте. Две задачи запускаются параллельно: одна читает текстовые файлы, другая — запускает программу, которая использует этот текст.

Посмотрите на код ниже и определите, что будет выведено:

import asyncio

texts = []


async def read_files() -> None:
await asyncio.sleep(2)
texts.append("Текст из файла")


async def process_text() -> None:
if not texts:
raise ValueError("Нет текста для обработки")
print(f"Использую: {texts[0]}")


async def start_app() -> None:
await process_text()


async def main() -> None:
await asyncio.gather(read_files(), start_app())


asyncio.run(main())



Разбор кода:
1. Объявление глобального списка `texts`:
- В начале программы объявляется пустой список texts, который позже будет заполняться текстом из файла.
- Он используется для хранения подгруженных данных.

2. Функция `read_files`:
- Эта асинхронная функция имитирует чтение файла, используя await asyncio.sleep(2) для создания задержки в 2 секунды.
- После ожидания в список texts добавляется строка "Текст из файла". Фактически, эта функция наполняет список, который должен использоваться в программе.

3. Функция `process_text`:
- Эта функция пытается использовать текст из глобального списка texts.
- Она проверяет, пуст ли список: if not texts:. Если в момент проверки списка он пуст, вызывается исключение ValueError("Нет текста для обработки").
- Если же в списке есть данные, программа выводит сообщение с текстом: Использую: {texts[0]}.

4. Функция `start_app`:
- Эта функция просто вызывает process_text, чтобы обработать текст.

5. Функция `main`:
- В функции main с помощью asyncio.gather одновременно запускаются две задачи:
- read_files() — задача чтения файла, которая длится 2 секунды.
- start_app() — задача, которая сразу же пытается обработать текст из списка texts.


Почему возникает ошибка:

Когда запускаются обе задачи с помощью asyncio.gather, они выполняются параллельно. Однако здесь есть ключевой момент: задача чтения файла (read_files) содержит задержку в 2 секунды. В то время как текст ещё не загружен, функция start_app() немедленно вызывает process_text, который пытается получить текст из списка texts. Но список в этот момент ещё пуст, так как данные ещё не успели подгрузиться. Это приводит к тому, что проверка if not texts: срабатывает, и выбрасывается исключение ValueError: Нет текста для обработки.

Итог:
Программа завершится с ошибкой:
ValueError: Нет текста для обработки



Как это исправить:

Чтобы избежать этой ошибки, необходимо дождаться завершения чтения файла перед обработкой текста. Например, можно сделать так, чтобы задача process_text запускалась только после того, как read_files завершится:

async def main() -> None:
await read_files() # Ждём завершения чтения файла
await start_app() # Только после этого запускаем обработку


Теперь текст гарантированно будет загружен перед его использованием, и программа завершится успешно:
Использую: Текст из файла
👍2🔥2
Реальная история

Не так давно у меня произошла похожая ситуация. Я предпочитаю хранить текст, который бот отправляет пользователям, в отдельных YAML-файлах. При запуске бота сначала читаются эти файлы, а затем бот начинает свою работу. Чтобы ускорить процесс запуска, я решил распараллелить задачи: пока бот стартует, файлы с текстами загружаются в оперативную память.

Однако я не учёл, что первое сообщение, которое бот отправляет при запуске, — это уведомление администратору о том, что бот запущен. Это сообщение, как и другие, находилось в YAML-файлах. В результате бот стартовал, пытался отправить уведомление, но не мог, потому что файлы ещё не были прочитаны.

Вывод: хранить текстовые файлы удобно для пользовательских сообщений, но критически важные сервисные сообщения лучше хранить непосредственно в коде. Это позволяет избежать ситуации, когда программа пытается использовать данные, которые ещё не успели загрузиться.
🔥4🤯1
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥5
Привет, друзья!

Прошла еще одна неделя, и у нас накопилось много интересных материалов: статьи, новости и полезные советы. Вот наш недельный дайджест:

Понедельник (07.10.2024) Дайджест за предыдущую неделю

Вторник (08.10.2024) Знаете ли вы, как Namespace и cgroups обеспечивают изоляцию в контейнеризации?

Среда (09.10.2024)

Четверг (10.10.2024) Obsidian LiveSync - совместная работа над проектной документацией

Пятница (11.10.2024) Пятничный кинорелакс

Суббота (12.10.2024) Задача

Воскресенье (13.10.2024) Текстовый разбор задачи


Спасибо, что остаетесь с нами! Надеемся, что эти материалы будут вам полезны. Удачи в новой неделе!

С уважением,
Команда канала "Код на салфетке".

#дайджест #материалы #новости #код_на_салфетке
🔥5👍1
Напиши свой ответ в комментариях. Если ты знаешь правильный ответ, то мы будем рады видеть тебя на нашем контесте.
🔥4
Знаете ли вы, как использовать Namespace и cgroups для обеспечения изоляции при контейнеризации?

Namespace изолирует системные аспекты, создавая отдельные пространства для каждого контейнера. Например:
- PID namespace: изолирует процессы
- Network namespace: изолирует сетевые интерфейсы
- Mount namespace: изолирует точки монтирования файловых систем

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

docker run -d --name appname \
--cpus 0.5 \
--memory 256m \
--memory-swap 512m \
--cpu-shares 512 \
imagename


В этом примере запуск Docker контейнера происходит с ограничениями cgroups:
--cpus 0.5 ограничивает использование CPU до 50% одного ядра
--memory 256m ограничивает память до 256 МБ
--memory-swap 512m устанавливает лимит подкачки в 512 МБ
--cpu-shares 512 задает относительный вес CPU

Так, namespace обеспечивает изоляцию на уровне системных ресурсов, а cgroups предоставляет контроль над количеством ресурсов, доступных контейнеру.

Код на салфетке x Кусочки кода
🔥7