c# - 什么决定了 "await"所花费的时间?

标签 c# asynchronous async-await

我有以下代码来从 TCP 流中读取字节(我已删除错误检查):

/// <summary>Awaitable. Reads a certain amount of bytes from a network stream. Returns false
/// on error</summary>
async Task<bool> readBytes (NetworkStream stream, byte []buffer, int totalBytes)
{
    int bytesRead = 0;

    while (true)
    {
        var br = await stream.ReadAsync (buffer, bytesRead, totalBytes - bytesRead);
        if (br == 0) return false;      // closed stream

        bytesRead += br;
        if (bytesRead >= totalBytes) return true;
    }
}

然后我在外部使用它来接收 4 个字节,其中包含传入数据的长度和数据正文(伪代码,我删除了错误检查和分配,只是为了给出一个想法):

success = await readBytes(stream, header, 4);
success = await readBytes(stream, data, dataLength);

presentDataToApp(data, dataLength);

客户端/服务器必须几乎实时交互(这是一个客户端应用程序调整多个参数的游戏,例如灯光)。例如,客户端有一个 WinForms slider ,并将所有更改传输到服务器应用程序中。移动 slider 时,一秒钟内可能会发生大量更新(从我的日志来看,它每秒发送数据大约 100 次)。

只要服务器(运行我粘贴的代码)通过 Visual Studio 运行,该代码就可以很好地实时运行。但是,当我在没有 Visual Studio 的情况下运行服务器应用程序(或使用 Ctrl+F5)时,通信开始严重滞后。

为了解决异步/等待问题,我克隆了通信类并通过线程运行它,删除了所有异步/等待函数。该代码现在在 Visual Studio 和独立版本中实时运行(因此这是与 async/await 相关的问题)。

为什么在这种情况下 async/await 通信会滞后? (肯定有一秒钟有很多等待)。什么决定了在没有准备好数据的等待之后等待的时间量? (我以为这是计时器分辨率,但无论我如何执行服务器应用程序,它在我的系统上似乎都是 1 毫秒)。

最佳答案

The client/server must interact in almost realtime

在您同时控制客户端和服务器的任何情况下,我始终推荐 SignalR。针对 SignalR 进行编程比原始套接字要容易得多。

This code works well and in realtime, as long as the server is run through Visual Studio. However, when I run the server app without Visual Studio (or using Ctrl+F5) the communication starts lagging badly.

这实在是太奇怪了。 VS 让你的代码运行得更快?我对此没有任何解释。

What does determine the amount of time waited after an await that doesn't have the data ready takes?

这里发生了一些事情,每件事都可能产生影响。

第一个是await捕获上下文并在该上下文上恢复。如果它是 UI 上下文,这尤其是一个问题。 At 100 updates per second, you're reaching the limit of what's practical 。如果您await s正在UI线程上恢复,您可以通过使用 ConfigureAwait(false) 来避免这种“千刀万剐的性能死亡” 。如果真的是await导致速度减慢的原因,请花些时间查看 Zen of Async video .

第二个是存在大量内存搅动。 readBytes每个数据包至少需要一个单独的数组(假设您重用 header 数组),并且还有多个 Task周围的实例。 如果分析表明问题是内存搅动,则consider using the new Memory<T> -based socket APIs that avoid the byte arrays, as well as the new ValueTask<T> -based APIs which avoid the Task allocations when the data is already arrived 。例如,.NET Core 2.1 Stream API ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken);如果分析表明问题是内存流失,但您尚未使用 .NET Core 2.1,那么您可以使用 SocketAsyncEventArgs APIs .

关于c# - 什么决定了 "await"所花费的时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56596440/

相关文章:

c# - Visual Studio 在打开 Web 应用程序解决方案时创建 bin 文件夹?

swift - MKDirections calculateETAWithCompletionHandler 执行延迟 Swift 2.0

arrays - 如何在范围循环上应用异步?

c# - C#中的同步任务执行

c# - 如何使这个异步? (异步、等待 - C#、MVC)

c# - 具有多个结果集的 Entity Framework 5 存储过程

c# - 在 WebBrowser 的 html 代码中查找并单击没有 ID 的按钮

c# - 最佳输出字典

javascript - Q.js 并行映射

javascript - 调用异步静态函数时出现语法错误