0Pricing
C# Academy · Урок

Компромиссы между пропускной способностью и задержкой

Балансируйте общий объем работы в секунду (пропускную способность) и время обработки одного элемента (задержку): сравнивайте поэлементную обработку, пакетирование и настройку степени параллелизма.

«Компромиссы между пропускной способностью и задержкой» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 3 уроков всего.

Пропускная способность и задержка

Определения:

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

Обработка отдельных элементов

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

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
  // Simulate small per-item cost
  static void HandleItem(int x)
  {
    // Fixed overhead per item
    Thread.SpinWait(20000); // tiny CPU work
  }

  public static void Main(string[] args)
  {
    int n = 200;
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < n; i++)
    {
      HandleItem(i);         // process immediately (no batching)
      // emit result right away (low latency style)
    }
    sw.Stop();
    Console.WriteLine("Per-item style: {0} ms for {1} items", sw.ElapsedMilliseconds, n);
  }
}

Пакетная обработка

Пакетная обработка сокращает повторяющиеся накладные расходы и повышает пропускную способность, но первые элементы ждут заполнения пакета, что увеличивает задержку.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

public class Program
{
  static void ProcessBatch(List<int> batch)
  {
    // Amortize overhead across the whole batch
    Thread.SpinWait(20000);        // one-time overhead
    for (int i = 0; i < batch.Count; i++)
    {
      // small per-record work
      int val = batch[i] * 2;
      if (val == int.MinValue) { } // keep compiler from dropping work
    }
  }

  public static void Main(string[] args)
  {
    int n = 200;
    int batchSize = 20;
    List<int> current = new List<int>(batchSize);

    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < n; i++)
    {
      current.Add(i);
      if (current.Count == batchSize)
      {
        ProcessBatch(current);
        current.Clear(); // emit results after the batch finishes
      }
    }
    if (current.Count > 0) ProcessBatch(current);
    sw.Stop();

    Console.WriteLine("Batch style: {0} ms for {1} items (batch={2})", sw.ElapsedMilliseconds, n, batchSize);
  }
}

Настройка параллелизма

Настройка MaxDegreeOfParallelism может повысить пропускную способность при работе с высокой нагрузкой на CPU; слишком высокое значение может навредить из-за переключений контекста.

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
  static void Work(int x)
  {
    // CPU-bound unit
    Thread.SpinWait(40000);
  }

  public static void Main(string[] args)
  {
    int[] data = new int[200];
    for (int i = 0; i < data.Length; i++) data[i] = i;

    foreach (int dop in new int[] { 1, 2, 4 })
    {
      var opt = new ParallelOptions();
      opt.MaxDegreeOfParallelism = dop;

      Stopwatch sw = Stopwatch.StartNew();
      Parallel.ForEach(data, opt, Work);
      sw.Stop();

      Console.WriteLine("DOP={0} -> {1} ms", dop, sw.ElapsedMilliseconds);
    }
  }
}

Идея микропакетов

Микропакеты помогают сбалансировать обе цели: обеспечивают более высокую пропускную способность, чем обработка отдельных элементов, и меньшую задержку, чем очень крупные пакеты.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
  static void ProcessBatch(List<int> batch)
  {
    Thread.SpinWait(15000); // small shared overhead
    for (int i = 0; i < batch.Count; i++) Thread.SpinWait(2000);
  }

  public static void Main(string[] args)
  {
    int n = 200;
    int micro = 5; // micro-batch size
    List<int> buf = new List<int>(micro);
    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < n; i++)
    {
      buf.Add(i);
      if (buf.Count == micro)
      {
        ProcessBatch(buf);
        buf.Clear(); // emit more frequently than big batches
      }
    }
    if (buf.Count > 0) ProcessBatch(buf);

    sw.Stop();
    Console.WriteLine("Micro-batch (size={0}): {1} ms", micro, sw.ElapsedMilliseconds);
  }
}

Советы по настройке

Руководство по настройке:

  • Измеряйте и мс на элемент, и элементы в секунду
  • Сначала попробуйте микропакеты
  • Постепенно увеличивайте параллелизм; следите за CPU и переключениями контекста
  • Ограничивайте очереди, чтобы избежать длительного ожидания и роста потребления памяти

Компромисс между пропускной способностью и задержкой

Быстрая проверка: какое изменение обычно повышает пропускную способность, но может увеличить задержку обработки отдельного элемента?

Итоги

Итоги: обработка отдельных элементов = низкая задержка и более низкая пропускная способность. Крупные пакеты и высокий DOP = более высокая пропускная способность и большая задержка. Микропакеты и тщательная настройка DOP помогают сбалансировать оба показателя.

Часто задаваемые вопросы

Урок «Компромиссы между пропускной способностью и задержкой» бесплатный?

Да — полный текст урока «Компромиссы между пропускной способностью и задержкой» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 3 уроков всего.

Чему я научусь в уроке «Компромиссы между пропускной способностью и задержкой»?

Балансируйте общий объем работы в секунду (пропускную способность) и время обработки одного элемента (задержку): сравнивайте поэлементную обработку, пакетирование и настройку степени параллелизма. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 3.

Сколько времени занимает урок «Компромиссы между пропускной способностью и задержкой»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Parallel.ForEach и PLINQ
  2. Производитель и потребитель с каналами (обзор)
  3. Компромиссы между пропускной способностью и задержкой
← Назад к C# Academy