Проблемы с производительностью при длительных вычислениях. net core - отдельный пул потоков - PullRequest
1 голос
/ 23 апреля 2020

Рассмотрим. Net Core 3.1 API со следующими конечными точками

  1. GET: / computation - выполняет задачу интенсивного вычисления CPU
  2. GET: / livecheck

Высокая нагрузка на конечную точку включения / вычисления: при высокой нагрузке на конечную точку «/ вычисления» 300 запросов в секунду, другие конечные точки замедляются по мере использования всех потоков.

Во время высокой нагрузки load, вызывающая конечную точку '/ livecheck', вернет запрос через 5-10 секунд, что слишком много.

Это проблема, потому что, если конечная точка / livecheck не отвечает вовремя, приложение убит. (AWS ECS, убивает контейнер, когда livecheck занимает более 5 секунд)

Возможно ли гарантировать, что конечная точка '/ livecheck' все еще возвращает данные, запустив конечную точку '/ computation' на отдельный пул потоков. Чтобы он не использовал все рабочие потоки и был доступен для других конечных точек?

Примечание:

  • '/ computation' должен быть возвращен как часть того же запроса , не хочу ставить его в очередь на фоновую задачу.

Любые другие решения также приветствуются.

Ответы [ 2 ]

0 голосов
/ 24 апреля 2020

Чтобы расширить мои комментарии под вопросом

Я все же рекомендую вам следовать рекомендациям, чтобы избежать блокировки вызовов .

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

Рассмотрим следующий пример:

void Computation()
{
    for (var i = 0; i < 300; i++)
    {
        Thread.Sleep(1);
    }   
}

void LiveCheck()
{
    Console.WriteLine("I'm alive.");
}

async Task Main()
{
    var tasks = new List<Task>();

    // Create 1000 blocking compuations to simulate busy thread pool
    // or thread pool starvation
    for (int i = 0; i < 1000; i++)
    {
        tasks.Add(Task.Run(Computation));       
    }

    // Simulate 3 seconds after thread pool is busy, execute livecheck
    Thread.Sleep(3000);

    var sw = Stopwatch.StartNew();
    await Task.Run(LiveCheck);
    sw.Stop();
    Console.WriteLine($"LiveCheck completed in {sw.Elapsed.TotalSeconds} seconds");

    await Task.WhenAll(tasks);
}

В большинстве случаев возвращаемый результат на моей машине выглядит следующим образом:

LiveCheck completed in 31.2030817 seconds

Если выгрузить вычисление из потока:

async Task Computation()
{
    for (var i = 0; i < 300; i++)
    {
        Thread.Sleep(1);

        // Yield thread every 50ms
        if ((i % 50) == 0)
        {
            await Task.Yield();
        }
    }   
}

Выходные данные обычно таковы:

LiveCheck completed in 2.4753268 seconds

Компромисс в данном случае один прогон вычисления будет медленнее, чем версия syn c.

0 голосов
/ 23 апреля 2020

Я бы предположил, что «интенсивное вычисление ЦП» выгружается в другое приложение и не выполняется в том же приложении, что и проверка в реальном времени. Может быть отправлено асинхронное сообщение c для запуска обработки вычислений, и приложение может подписаться на законченное или неудачное событие из приложения обработки. Таким образом, тяжелая обработка не повлияет на время отклика веб-API.

Более того, вы можете докеризировать приложения.

...