Що таке синхронний та асинхронний колбек у C#?

Що таке синхронний та асинхронний колбек у C#?
Переклад 8 хв. читання
28 серпня 2023

Ця стаття допоможе вам зрозуміти синхронний та асинхронний колбек в C# та їх доцільне використання, включаючи приклади та міркування щодо ефективної обробки короткотривалих завдань, операцій вводу/виводу, паралелізму, швидкості реакції та масштабованості.

Вступ

Що таке асинхронний та синхронний колбек у C#? Коли та в яких випадках можна використовувати синхронні та асинхронні методи?

Загальні відомості

У C# синхронний та асинхронний колбек - це механізми, які використовуються для завершення виконання задачі або події. Функції зворотного виклику дозволяють вказати функцію або делегат, який буде виконано після завершення певної операції. Вони зазвичай використовуються для вирішення завдань, виконання яких може зайняти значний проміжок часу, наприклад, операцій вводу/виводу або мережевих запитів.

Основна відмінність між синхронними та асинхронними функціями зворотного виклику полягає в тому, як вони обробляють потік виконання і потенційно блокують викликаючий потік.

1. Синхронний колбек

Синхронний колбек - це функція або делегат, що виконується негайно і блокує потік, що її викликає, до його завершення. Іншими словами, коли викликається синхронний колбек, програма чекає на його завершення, перш ніж перейти до наступного завдання. Це може призвести до потенційних проблем з продуктивністю і блокуванням основного потоку, що може зробити програму повільнішою.

Приклад синхронного колбеку в C#:

public void SynchronousCallbackExample()
{
    Action<string> callback = message => Console.WriteLine(message);
    DoSomethingSynchronously(callback);
}

public void DoSomethingSynchronously(Action<string> callback)
{
    // Simulate a time-consuming operation
    for (int i = 0; i < 5; i++)
    {
        callback($"Iteration {i}");
        Thread.Sleep(1000); // Simulate work
    }
}

2. Асинхронний колбек

З іншого боку, асинхронний колбек використовується для виконання коду без блокування викликаючого потоку. Замість того, щоб чекати на завершення зворотного виклику, викликаючий потік може продовжувати виконувати інші завдання, поки колбек виконується у фоновому режимі. Такий підхід допомагає підтримувати швидкість реакції програми та може призвести до кращого використання системних ресурсів.

Приклад асинхронного колбеку на C#:

public async Task AsynchronousCallbackExample()
{
    Func<string, Task> callbackAsync = async message =>
    {
        await Task.Delay(2000); // Simulate non-blocking work asynchronously
        Console.WriteLine(message);
    };
    await DoSomethingAsynchronously(callbackAsync);
}

public async Task DoSomethingAsynchronously(Func<string, Task> callbackAsync)
{
    var tasks = new Task[15];

    for (int i = 0; i < 15; i++)
    {
        tasks[i] = callbackAsync($"Iteration {i}");
        //await Task.Delay(1000);
    }

    await Task.WhenAll(tasks);
}

Використовуючи делегат Func<string, Task> і масив об'єктів Task, ми досягаємо одночасного виконання асинхронних операцій без блокування основного потоку. Рядок await Task.WhenAll(tasks) гарантує, що програма продовжить роботу після завершення всіх асинхронних завдань.

Загалом, асинхронні виклики є кращими у сценаріях, де залучені довготривалі операції, оскільки вони допомагають покращити відгук програми та запобігають блокуванню основного потоку.

Мета використання функції Func та масиву Task на прикладі.

1. Використання функції Func для асинхронних колбеків

  • В асинхронному програмуванні ми хочемо виконувати завдання паралельно, не блокуючи основний потік.
  • Func<string, Task> - це делегат, який представляє асинхронну функцію, що отримує параметр string і повертає Task. Цей делегат використовується для визначення асинхронного колбеку, який може виконуватися паралельно.

2. Визначення асинхронного колбеку

  • Функція callbackAsync описується за допомогою делегату Func<string, Task>. Вона являє собою асинхронну операцію, яка імітує неблокуючу роботу шляхом затримки на певний час, а потім запису повідомлення в консоль.
  • Використання масиву завдань для зберігання асинхронних операцій

3. Використання масиву завдань для зберігання асинхронних операцій

  • Для одночасного виконання декількох асинхронних операцій ми створюємо масив об'єктів Task для зберігання цих завдань.

4. Цикл і додавання завдань до масиву

  • Усередині методу DoSomethingAsynchronously ми повторюємо цикл і створюємо декілька завдань, викликаючи функцію callbackAsync. Кожне завдання являє собою незалежну асинхронну операцію.

5. Одночасне виконання з використанням Task.WhenAll

  • Після додавання всіх завдань до масиву, ми використовуємо Task.WhenAll(tasks) для асинхронного очікування завершення всіх завдань. Цей метод повертає нову задачу, яка завершується, коли завершаться всі надані задачі.

Коли і в яких сценаріях слід використовувати синхронні та асинхронні методи?

Вибір між використанням синхронних (sync) та асинхронних (async) методів залежить від конкретного сценарію та вимог програми. Ось деякі рекомендації, які допоможуть визначити, коли використовувати кожний з підходів.

Синхронні методи

I. Прості та швидкі завдання: Для короткочасних, неблокуючих операцій, які не вимагають значного очікування, синхронні методи можуть бути доречними. Ці методи легше читати та розуміти

II. Графічний інтерфейс (UI): У програмах з графічним інтерфейсом (UI) деякі операції повинні виконуватися у головному потоці інтерфейсу. Синхронні методи можна використовувати для задач, які повинні взаємодіяти з інтерфейсом користувача.

III. Послідовна логіка: Коли код базується на послідовному виконанні, і нам потрібно переконатися, що певні завдання завершені, перш ніж рухатися далі, синхронні методи можуть спростити наш код.

Асинхронні методи

I. Операції, пов'язані із вводом-виводом (I/O): При виконанні операцій вводу-виводу (таких як читання/запис файлів, мережеві запити або запити до бази даних) асинхронні методи є корисними. Вони дозволяють виконувати інші завдання під час очікування завершення операцій вводу/виводу, що покращує відклик програми.

II. Конкурентність та паралельність: Асинхронні методи необхідні для завдань, які можуть виконуватися одночасно або паралельно, наприклад, для обробки декількох запитів або великих обсягів даних.

III. Масштабованість: У серверних програмах асинхронні методи можуть допомогти обробляти більшу кількість вхідних запитів без створення нового потоку для кожного запиту, що було б неефективно і ресурсоємно.

IV. Довготривалі завдання: Для операцій, які займають значну кількість часу, таких як складні обчислення або фонова обробка, асинхронні методи можуть запобігти зависанню програми.

V. Програмування на основі подій: Асинхронні методи часто використовуються в подієво-керованому програмуванні, де нам потрібно реагувати на події, не блокуючи основний потік.

VI. Багатопотоковість: Асинхронні методи можуть спростити багатопотокові сценарії, дозволяючи виконувати декілька завдань одночасно без прямого управління потоками.

Загалом, асинхронним методам надається перевага у сценаріях, що включають потенційно довготривалі або блокуючі операції, паралелізм, швидкість відгуку та масштабованість. Однак важливо зазначити, що використання асинхронного програмування вносить певні складнощі, такі як обробка виключень і синхронізація, якими слід ретельно керувати.

Обираючи між синхронними та асинхронними методами, враховуйте характер завдання, потенційний вплив на швидкість відгуку програми та загальну архітектуру. Збалансований підхід може включати в себе комбінацію синхронних та асинхронних методів в залежності від конкретних потреб різних частин нашого коду.

Цікаві моменти

Одна безглузда помилка, з якою я зіткнувся:

The asynchronous action method returns a task which cannot be executed synchronously.

Це повідомлення про помилку зазвичай виникає, коли ми намагаємося викликати асинхронний метод синхронно, що заборонено в .NET. Асинхронні методи, які повертають Task, призначені для асинхронного очікування, щоб уникнути блокування потока виклику.

Для виправлення цієї помилки ми повинні дотримуватися шаблону асинхронного програмування і використовувати ключове слово await для асинхронного очікування завдання на завершення. Ось приклад того, як виправити цю помилку:

using System;
using System.Threading.Tasks;
using System.Web.Mvc;

public class MyController : Controller
{
    public async Task<ActionResult> MyAction()
    {
        // Perform asynchronous operations here
        await DoAsyncWork();

        return View();
    }

    public async Task DoAsyncWork()
    {
        // Simulate a time-consuming operation asynchronously
        await Task.Delay(1000);
    }
}

У вищезазначеному прикладі метод MyAction позначений як async і повертає Task<ActionResult>. Всередині методу ми використовуємо ключове слово await для асинхронного очікування завершення методу DoAsyncWork, який також позначений як async.

Дотримуючись цього шаблону, ми гарантуємо, що наші асинхронні методи очікують асинхронно, запобігаючи блокуванню потоку виклику та уникненню повідомлення про помилку.

Джерело: What is Synchronous and Asynchronous Callback in C#?
Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація