Это потокобезопасная очередь для передачи сообщений между задачами без ручных блокировок и сложной синхронизации.
Что важно знать:
• Работает без ручных блокировок и сложных синхронных вызовов.
• Позволяет автоматически замедлять отправку при перегрузке памяти.
• Обеспечивает плавную передачу данных между параллельными задачами.
Так вы получаете готовый «из коробки» механизм асинхронной очереди с естественным управлением нагрузкой без лишнего кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤5👍3🤝1
Понятный разбор того, как на самом деле работает async/await в C#!
В этой статье:
• Чем асинхронность отличается от запуска работы в отдельном потоке
• Когда await освобождает поток, а когда выполнение продолжается синхронно
• Как компилятор превращает асинхронный метод в машину состояний
➡️ C# Ready | #статья
В этой статье:
• Чем асинхронность отличается от запуска работы в отдельном потоке
• Когда await освобождает поток, а когда выполнение продолжается синхронно
• Как компилятор превращает асинхронный метод в машину состояний
Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤4🔥3
Почему yield return в C# выполняется не сразу?
Метод с yield выглядит как обычный метод:
Но при вызове код внутри ещё не выполняется:
В консоли сначала будет:
А строка start появится только тогда, когда коллекцию начнут реально перебирать:
И вот тогда выполнение пойдёт пошагово:
Это важно помнить, если внутри iterator-метода есть чтение файла, запрос к базе, логирование или любая другая побочная логика.
Например, такой код может выполнить запрос не там, где кажется:
LoadUsers() может начать работу только на foreach, а не на первой строке.
Если нужно зафиксировать результат сразу, материализуй последовательность:
yield return создаёт ленивую последовательность. Код внутри запускается при перечислении, а не при вызове метода.
➡️ C# Ready | #совет
Метод с yield выглядит как обычный метод:
IEnumerable<int> GetNumbers()
{
Console.WriteLine("start");
yield return 1;
yield return 2;
}
Но при вызове код внутри ещё не выполняется:
var numbers = GetNumbers();
Console.WriteLine("created");
В консоли сначала будет:
created
А строка start появится только тогда, когда коллекцию начнут реально перебирать:
foreach (var number in numbers)
{
Console.WriteLine(number);
}
И вот тогда выполнение пойдёт пошагово:
start
1
2
Это важно помнить, если внутри iterator-метода есть чтение файла, запрос к базе, логирование или любая другая побочная логика.
Например, такой код может выполнить запрос не там, где кажется:
var users = LoadUsers();
DoSomething();
foreach (var user in users)
{
Console.WriteLine(user.Name);
}
LoadUsers() может начать работу только на foreach, а не на первой строке.
Если нужно зафиксировать результат сразу, материализуй последовательность:
var users = LoadUsers().ToList();
yield return создаёт ленивую последовательность. Код внутри запускается при перечислении, а не при вызове метода.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍3🔥2
Простая и популярная статья о создании Telegram-бота на C#!
В этой статье:
• Как создать бота через BotFather и подключить его к проекту
• Как принимать сообщения пользователя и отправлять ответы
• Как собрать базу, от которой уже можно развивать своего бота дальше
➡️ C# Ready | #статья
В этой статье:
• Как создать бота через BotFather и подключить его к проекту
• Как принимать сообщения пользователя и отправлять ответы
• Как собрать базу, от которой уже можно развивать своего бота дальше
Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4🔥3
Шпаргалка по недооценённым LINQ-методам в C#!
Например, SequenceEqual() помогает сравнить две последовательности по элементам, ToLookup() создаёт удобную группировку для быстрого доступа по ключу, а GroupJoin() полезен, когда нужно связать две коллекции и получить вложенный результат.
На картинке 5 LINQ-методов с короткими примерами кода: SequenceEqual, Aggregate, GroupJoin, ToLookup и Intersect.
Сохрани, чтобы не потерять!
➡️ C# Ready | #ресурс
Например, SequenceEqual() помогает сравнить две последовательности по элементам, ToLookup() создаёт удобную группировку для быстрого доступа по ключу, а GroupJoin() полезен, когда нужно связать две коллекции и получить вложенный результат.
На картинке 5 LINQ-методов с короткими примерами кода: SequenceEqual, Aggregate, GroupJoin, ToLookup и Intersect.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍7🔥6
Опа, тут бывший сеньор одного из IT-отделов Яндекса Игорь Никитин выкатил целый канал про Python — и это лучшее, что есть в рунете по теме.
Качественные гайды. Советы от известных прогеров. Тематические мемасы. Короче, ничего лишнего.
Хватит душить питона, учись его кодить: https://t.me/+IzIPzvoa7p40ZTUy 🐍
Качественные гайды. Советы от известных прогеров. Тематические мемасы. Короче, ничего лишнего.
Хватит душить питона, учись его кодить: https://t.me/+IzIPzvoa7p40ZTUy 🐍
👎9
Собираем простую очередь фоновых задач!
Иногда в приложении нужно отложить работу: отправить email, записать аудит, обработать файл или выполнить тяжёлую операцию после ответа пользователю.
Для этого можно собрать небольшую очередь на Channel<T>.
Сначала заведём интерфейс:
Реализация будет хранить задачи внутри Channel:
Добавление задачи:
Чтение задач:
Теперь можно положить работу в очередь:
А отдельный воркер будет выполнять задачи:
В ASP.NET Core такую логику обычно выносят в BackgroundService:
Такой подход помогает не держать HTTP-запрос открытым, если работу можно выполнить после ответа пользователю.
➡️ C# Ready | #практика
Иногда в приложении нужно отложить работу: отправить email, записать аудит, обработать файл или выполнить тяжёлую операцию после ответа пользователю.
Для этого можно собрать небольшую очередь на Channel<T>.
Сначала заведём интерфейс:
public interface ITaskQueue
{
ValueTask EnqueueAsync(Func<CancellationToken, Task> job);
IAsyncEnumerable<Func<CancellationToken, Task>> ReadAllAsync(
CancellationToken token
);
}
Реализация будет хранить задачи внутри Channel:
using System.Threading.Channels;
public sealed class TaskQueue : ITaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _channel =
Channel.CreateUnbounded<Func<CancellationToken, Task>>();
Добавление задачи:
public ValueTask EnqueueAsync(Func<CancellationToken, Task> job)
{
return _channel.Writer.WriteAsync(job);
}
Чтение задач:
public IAsyncEnumerable<Func<CancellationToken, Task>> ReadAllAsync(
CancellationToken token
)
{
return _channel.Reader.ReadAllAsync(token);
}
}
Теперь можно положить работу в очередь:
await queue.EnqueueAsync(async token =>
{
await emailSender.SendAsync(user.Email, token);
});
А отдельный воркер будет выполнять задачи:
await foreach (var job in queue.ReadAllAsync(token))
{
await job(token);
}
В ASP.NET Core такую логику обычно выносят в BackgroundService:
protected override async Task ExecuteAsync(CancellationToken token)
{
await foreach (var job in queue.ReadAllAsync(token))
{
await job(token);
}
}
Такой подход помогает не держать HTTP-запрос открытым, если работу можно выполнить после ответа пользователю.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍3🔥3