Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果.NET Task.Run用于运行CPU绑定的任务,那么';在后台启动IO绑定任务的正确方法是什么?_C#_.net_Multithreading_Task - Fatal编程技术网

C# 如果.NET Task.Run用于运行CPU绑定的任务,那么';在后台启动IO绑定任务的正确方法是什么?

C# 如果.NET Task.Run用于运行CPU绑定的任务,那么';在后台启动IO绑定任务的正确方法是什么?,c#,.net,multithreading,task,C#,.net,Multithreading,Task,我从头开始编写了一个网络服务器应用程序,因此没有IIS或Windows窗体。我一直在使用Task.Run将对网络会话生命周期的控制权移交给后台运行 类似于 while (true) { var tcpClient = tcpListener.Accept... Task.Run(() => ProcessSession(tcpClient)); } ……然后 public async Task ProcessSession(TcpClient tcpClient) {

我从头开始编写了一个网络服务器应用程序,因此没有IIS或Windows窗体。我一直在使用Task.Run将对网络会话生命周期的控制权移交给后台运行

类似于

while (true)
{
    var tcpClient = tcpListener.Accept...
    Task.Run(() => ProcessSession(tcpClient));
}
……然后

public async Task ProcessSession(TcpClient tcpClient)
{
    ...
    await tcpClient.GetStream().ReadAsync(...)
    ...
}
我的希望是,当我在ProcessSession中对网络I/O执行异步/等待时,工作线程将被释放,直到I/O完成

我发现我的服务器软件陷入了只有几百个连接的困境,以至于客户端尝试连接时超时,或者如果他们连接起来,他们的网络吞吐量会非常慢。我希望每台服务器能处理数千个连接


当我查看ThreadPool.Get(Max/Available)Threads时,这里看起来并没有发生什么变化。Process.GetCurrentProcess().Threads.Count仅为低数,因此它不像是每个连接的线程。它只是陷入了困境。

利用网络堆栈的内置异步是正确的解决方案,看起来这就是您在使用TcpClient时所做的


考虑到你“陷入困境”,调查瓶颈在哪里。没有人能够在不知道问题是什么的情况下解决性能问题。你的内存空间是什么样子的?时间花在哪里?perfmon说在您的服务器进程中发生了什么?

如果
ProcessSession
确实没有阻塞,那么您可以调用它:

while (true)
{
    var tcpClient = tcpListener.Accept...
    ProcessSession(tcpClient);
}
并扔掉由此产生的任务。确保记录所有错误


将名称更改为
ProcessSessionAsync

,那么您认为该任务可以使用I/O绑定代码运行吗?有没有其他方法可以触发I/O绑定代码,以使async/await工作,并且不会导致每个连接都有线程?看看Task Manager,有大量内存被用于6.5 GB的机箱,其中网络服务器使用的是3.5 GB。看看perfmon,它正在以每秒10百万字节的速度分配。第0代堆为280 MB。第1代堆是300 MB。第2代堆是750MB。大对象堆是200GB。对于网络缓冲区,我使用了一个内存流的ConcurrentQueue,这样GC就不会一直在处理不断流入和流出的网络字节。我假设LOH大小是一个输入错误,应该是200MB。即便如此,对于应用程序正在运行的连接数,堆中的内存量是否是您期望在应用程序中拥有的?如果这是一个32位进程,那么您对内存空间施加了很大的压力。更清楚地定义什么是“陷入困境”也很有用。您面临的请求延迟是否越来越高?可接受的阈值是多少?需要多少连接才能超过该阈值?它是否与服务器的另一个特性有关(例如,跨特定边界消耗的内存)?请参见问题。仅从其他同步代码中触发这些内容是否有任何不利之处?等待泡沫将上升到哪里?没什么好担心的?Task.Run也是一种从其他异步代码中激发内容的方法。所以这本身不是问题。我在这里这样做的方式只有一个缺点,那就是如果ProcessSession确实阻塞(尽管它不应该阻塞),或者如果它在异步之前运行大量计算,那么接受新客户机将会延迟。因此,使用Task更安全。以少量开销为代价运行。;不知道你说的“泡泡”是什么意思。这两种样式中的错误都会被丢弃。你必须注意记录它们。