c# - 为什么我的异步代码调试的时候是同步运行的?

标签 c# visual-studio asynchronous async-await

我正在尝试使用异步功能实现一个名为 ReadAllLinesAsync 的方法。我已经生成了以下代码:

private static async Task<IEnumerable<string>> FileReadAllLinesAsync(string path)
{
    using (var reader = new StreamReader(path))
    {
        while ((await reader.ReadLineAsync()) != null)
        {

        }
    }
    return null;
}

private static void Main()
{
    Button buttonLoad = new Button { Text = "Load File" };
    buttonLoad.Click += async delegate
    {
        await FileReadAllLinesAsync("test.txt"); //100mb file!
        MessageBox.Show("Complete!");
    };

    Form mainForm = new Form();
    mainForm.Controls.Add(buttonLoad);
    Application.Run(mainForm);
}

我希望列出的代码异步运行,事实上,确实如此!但只有当我没有 Visual Studio 调试器运行代码时。

当我附加 Visual Studio 调试器运行代码时,代码同步运行,阻塞主线程导致 UI 挂起。

我已经尝试并成功地在三台机器上重现了这个问题。每个测试都是在 64 位机器(Windows 8 或 Windows 7)上使用 Visual Studio 2012 进行的。

我想知道为什么会出现这个问题以及如何解决它(因为在没有调试器的情况下运行可能会阻碍开发)。

最佳答案

问题是您在一个什么都不做的紧密循环中调用 await reader.ReadLineAsync() - 除了在每次等待之后将执行返回到 UI 线程,然后再重新开始。仅当 ReadLineAsync() 尝试读取一行时,您的 UI 线程才可以自由处理 Windows 事件。

要解决此问题,您可以将调用更改为 await reader.ReadLineAsync().ConfigureAwait(false)

await 等待异步调用完成并将执行返回到首先调用 await 的同步上下文。在桌面应用程序中,这是 UI 线程。这是一件好事,因为它允许您直接更新 UI,但如果您在 await 之后立即处理异步调用的结果,可能会导致阻塞。

您可以通过指定 ConfigureAwait(false) 来更改此行为,在这种情况下,执行将在不同的线程中继续,而不是在原始同步上下文中。

即使不是紧密循环,您的原始代码也会阻塞,因为循环中处理数据的任何代码仍会在 UI 线程中执行。要在不添加 ConfigureAwait 的情况下异步处理数据,您应该在使用例如创建的任务中处理数据。 Task.Factory.StartNew 并等待该任务。

以下代码不会阻塞,因为处理是在不同的线程中完成的,允许 UI 线程处理事件:

while ((line= await reader.ReadLineAsync()) != null)
{
    await Task.Factory.StartNew(ln =>
    {
        var lower = (ln as string).ToLowerInvariant();
        Console.WriteLine(lower);
     },line);
}

关于c# - 为什么我的异步代码调试的时候是同步运行的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17507374/

相关文章:

c# - 为什么我必须使用(async method).result而不是await(async method)?

c# - 将 XML 中的后代查询到 Linq

c# - MVC3 数据绑定(bind)

c# - 异步和等待 - 控制台、Windows 窗体和 ASP.NET 之间的区别

javascript - 为什么有同步和异步模块的规范?

c++ - Visual Studio 仅在一个线程中进行调试

c# - 在 autofac 中可视化依赖树深度

c# - 为什么我的表单在关闭时仍然向列表中添加一个项目?

visual-studio - nopcommerce 3.40 主题改变

visual-studio - 带 HTTPS 的 TeamCity Visual Studio 插件