【问题标题】:If .NET Task.Run is for running CPU-bound tasks, what's the right way to start IO-bound tasks to run in the background?如果 .NET Task.Run 用于运行 CPU 密集型任务,那么启动 IO 密集型任务以在后台运行的正确方法是什么?
【发布时间】:2015-02-03 20:33:48
【问题描述】:

我从头开始编写了一个网络服务器应用程序,所以没有 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 执行 async / await 时,工作线程将被释放,直到 I/O 完成。

我发现我的服务器软件在只有几百个连接的情况下陷入困境,以至于客户端尝试连接时超时,或者如果他们连接到网络吞吐量确实很慢。我希望每台服务器处理数千个连接。

当我查看 ThreadPool.Get(Max/Available)Threads 时,它看起来并没有发生太多事情。 Process.GetCurrentProcess().Threads.Count 只有几十个,所以它不像每个连接一个线程。它只是陷入困境。

【问题讨论】:

标签: c# .net multithreading task


【解决方案1】:

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

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

【讨论】:

  • 那么您认为使用 I/O 绑定代码的 Task.Run 是否可行?有没有其他方法可以触发 I/O 绑定代码,以便 async / await 工作并且不会导致每个连接线程?
  • 查看任务管理器,盒子内存占用很大,6.5GB,其中网络服务器占用3.5GB。
  • 查看 perfmon,它分配的数以百万字节/秒为单位。 Gen 0 堆为 280 MB。第 1 代堆为 300 MB。第 2 代堆为 750 MB。大对象堆为 200 GB。对于网络缓冲区,我使用了 MemoryStreams 的 ConcurrentQueue,这样 GC 就不会一直运行以处理不断进出的网络字节流。
  • 我假设 LOH 大小是一个错字,应该是 200MB。即便如此,堆中的内存量是您希望应用程序中运行的连接数所具有的内存量吗?如果这是一个 32 位进程,那么您正在对内存空间施加巨大压力。
  • 更清楚地定义什么是“陷入困境”也很有用。您面临的请求延迟是否越来越高?可接受的阈值是多少?超过该阈值需要多少个连接?它是否与服务器的另一个特征相关联(例如,跨越特定边界的消耗内存)?
【解决方案2】:

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

while (true)
{
    var tcpClient = tcpListener.Accept...
    ProcessSession(tcpClient);
}

并丢弃生成的任务。请务必记录所有错误。

将名称更改为ProcessSessionAsync

【讨论】:

  • 从其他同步代码中触发这些东西有什么缺点吗? await 会冒泡到哪里?没什么好担心的?
  • Task.Run 也是一种从其他异步代码中触发内容的方法。所以这本身不是问题。我在这里做的方式只有一个缺点,那就是如果 ProcessSession 确实阻塞,尽管它不应该阻塞,或者如果它在异步之前运行大量计算,接受新客户端将被延迟。因此以少量开销为代价使用 Task.Run 更安全。不知道你所说的“冒泡”是什么意思。两种样式都会丢弃错误。您必须小心记录它们。
猜你喜欢
  • 1970-01-01
  • 2021-01-02
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 2022-08-06
  • 2019-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多