gpt4 book ai didi

c# - ASP.NET Core和Kestrel线程池中的异步处理

转载 作者:太空狗 更新时间:2023-10-29 17:40:01 25 4
gpt4 key购买 nike

我是Java领域的新手,对ASP.NET Core和C#还是陌生的,我对async/await关键字的工作方式有些困惑:This article解释说,如果将方法标记为异步,则意味着

"this method contains control flow that involves awaiting asynchronous operations and will therefore be rewritten by the compiler into continuation passing style to ensure that the asynchronous operations can resume this method at the right spot.” The whole point of async methods it that you stay on the current thread as much as possible



因此,我认为这是在异步方法及其调用程序之间传递控制权的一种非常酷的方法,该调用程序在 相同的线程上运行,该线程在字节码/虚拟机级别上实现。我的意思是我期望下面的代码
public static void Main(string[] args)
{
int delay = 10;
var task = doSthAsync(delay);
System.Console.WriteLine("main 1: " + Thread.CurrentThread.ManagedThreadId);
// some synchronous processing longer than delay:
Thread.Sleep(2 * delay)
System.Console.WriteLine("main 2: " + Thread.CurrentThread.ManagedThreadId);
task.Wait();
}

public static async Task<String> doSthAsync(int delay)
{
System.Console.WriteLine("async 1: " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(delay);
System.Console.WriteLine("async 2: " + Thread.CurrentThread.ManagedThreadId);
return "done";
}

会写

异步1:1
主要1:1
主2:1
异步2:1

通过使用 doSthAsync关键字将控制权从 Main传递到 await,然后再通过 doSthAsync返回 task.Wait()(所有这些都在单个线程上发生)。

但是实际上上面的代码可以打印

异步1:1
主要1:1
异步2:4
主2:1

这意味着,如果当前线程正忙,这仅仅是将“异步”方法委派给单独线程的一种方法,这几乎与与完全相反,即所提到的文章所指出的:

The “async” modifier on the method does not mean “this method is automatically scheduled to run on a worker thread asynchronously”



因此,由于异步方法的“延续”显然是,或者至少是 可能已安排计划在其他线程上运行,所以我有一些问题似乎对于C#应用程序可伸缩性至关重要:

每个异步方法都可以在新生成的线程上运行,还是C#运行时为此目的维护一个特殊的线程池,在后一种情况下,我如何控制该池的大小?
更新:,感谢@Servy我现在知道在CMD行应用程序的情况下它将是线程池线程,但我仍然不知道如何控制这些线程池线程的数量。

如果使用ASP.NET Core,该如何处理:如何控制Kestrel用于执行异步 Entity Framework 操作或其他(网络)I/O的线程池的大小?它用于接受HTTP请求的线程池是否相同?
更新:感谢Stephen Cleary的thisthis article支持,我现在知道默认情况下它将默认“单线程运行”,即:在任何给定时间,给定的SynchronizationContext中将只有一个线程HTTP请求,但是当某些异步操作被标记为已完成并且任务恢复时,可以将该线程切换到另一个线程。我还了解到,可以使用 ConfigureAwait(false)将“从给定SynchronizationContext之外”的任何异步方法分派(dispatch)到线程池线程。仍然,我不知道如何控制线程池线程的数量,以及它是否与Kestrel用来接受HTTP请求的池相同。

据我了解,如果所有I/O都正确地异步完成,那么这些池的大小(实际上是1个线程池还是2个单独的线程池)与向外部资源打开的传出连接数量无关像DB,对不对? (运行异步代码的线程将不断接受新的HTTP请求,并且由于它们的处理,它们将尽快打开出站连接(与DB或某些Web服务器从Web上获取某些资源),而不会受到任何阻塞)
反过来,这意味着如果我不想杀死我的数据库,则应该为其连接池设置一个合理的限制,并确保等待可用连接也以异步方式完成,对吗?
假设我是对的,我仍然希望能够限制线程池线程的数量,以防错误地同步执行了一些长时间的I/O操作,以防止由于大量的I/O操作而产生大量的线程。线程在此同步操作上被阻止(即:我认为最好限制我的应用程序的性能,而不是由于此类错误而使它产生疯狂的线程数)

我也有一个“出于好奇”的问题:为什么实际上未实现异步/等待,以在同一线程上执行异步任务?我不知道如何在Windows上实现它,但是在Unix上可以使用选择/轮询系统调用或信号来实现,所以我相信也有一种方法可以在Windows上实现,这将是一种非常酷的语言功能确实如此。
更新:如果我正确理解,那么如果我的SynchronizationContext不为null,这几乎就是工作原理:即代码将“单线程运行”:在任何给定时间,给定SynchronizationContext中将只有一个线程。但是,它的实现方式将使同步方法等待异步任务陷入僵局,对吗? (运行时将计划将任务标记为已完成,以在等待该任务完成的同一线程上运行)

谢谢!

最佳答案

await使用SynchronizationContext.Current的值来安排继续。在控制台应用程序中,默认情况下没有当前的同步上下文。因此,仅使用线程池线程来调度连续性。在具有消息循环的应用程序(例如winforms,WPF或winphone应用程序)中,消息循环会将当前同步上下文设置为将所有消息发送到消息循环的同步上下文,从而在UI线程上运行它们。

在ASP应用程序中,还将有一个当前的同步上下文,但这不是一个特定的线程。相反,当需要为同步上下文运行下一条消息时,它将获取一个线程池线程,使用正确的请求的请求数据对其进行设置,然后运行该消息。这意味着在ASP应用程序中使用同步上下文时,您会知道一次运行的操作不会超过一个,但不一定是一个线程来处理每个响应。

关于c# - ASP.NET Core和Kestrel线程池中的异步处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41101797/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com