首页 > 解决方案 > 长时间运行的计算 .net 核心的性能问题 - 单独的线程池

问题描述

考虑具有以下端点的 .Net Core 3.1 API

  1. GET : /computation - 执行 CPU 密集型计算任务
  2. 获取:/livecheck

/computation 端点上的高负载:当“/computation”端点上的负载很高时,每秒 300 个请求,其他端点会因为所有线程都用完而减慢。

在高负载期间调用“/livecheck”端点将在 5-10 秒内返回一个请求,这太多了。

这是一个问题,因为如果“/livecheck”端点没有按时响应,应用程序就会被杀死。(AWS ECS,当 livecheck 超过 5 秒时会杀死容器)

是否可以通过在单独的线程池上运行“/computation”端点来确保“/livecheck”端点仍然返回数据。这样它就不会用完所有工作线程并且它们可用于其他端点?

笔记 :

任何其他解决方案也欢迎。

标签: c#asp.net-core.net-coreasp.net-core-webapi

解决方案


扩展我有问题的评论

我仍然建议您遵循最佳做法以避免阻塞呼叫

但是现在,让我们假设你真的不能,那么你至少应该从线程中卸载计算,只要它适合给处理器时间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

这里的权衡是单次计算将比同步版本慢。


推荐阅读