+-
长时间运行计算的性能问题.net core - 单独的线程池

考虑一个带有以下端点的.Net Core 3.1 API

GET : 计算 - 执行一个CPU密集型计算任务。 GET:直播检查

计算端点的高负载:当'计算'端点有高负载时,每秒300个请求,其他端点会因为所有线程被用完而变慢。

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

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

是否可以通过在一个单独的线程池上运行 "计算 "端点来确保 "livecheck "端点仍然返回数据。这样,它就不会用掉所有的工作线程,而这些线程可以用于其他端点?

注意。

'computation'必须作为同一个请求的一部分来返回,不要把它排到后台任务。

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

0
投票

我建议将 "cpu密集型计算 "卸载到另一个应用中,而不是和实时检查在同一个应用中完成。可以发送一条异步消息来触发计算处理开始,而应用程序可以从处理应用程序中订阅一个完成或失败的事件。这样大量的处理就不会影响到web api的响应时间。

比这更好的是,你可以把应用docker化。

0
投票

扩展一下我在问题下的评论

我还是建议你按照 避免屏蔽电话的最佳做法.

但现在,让我们假设你 真的 不能,那么你至少应该卸载 计算 在适合的时候从线程中移除,以便让处理器有时间处理 现场检查.

考虑这个例子。

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

如果offload 计算 从线程。

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

輸出通常是: 权衡 这里是单次运行的计算会比同步版慢。