【问题标题】:C# async await simple issueC#异步等待简单问题
【发布时间】:2015-06-16 08:10:46
【问题描述】:

我只是在学习任务和 async/await 实现,我正在为一个简单的代码示例而苦苦挣扎,所以我希望有人可以分享一些关于正在发生的事情的信息。

代码如下:

public async Task<string> DoStuff()
{
    Console.WriteLine("Long running op started");
    var myString = await Task<string>.Run(() =>
    {
        var result = "Test";
        for (int counter = 0; counter < 5000; counter++)
        {
            Console.WriteLine(counter);
        }
        return (result);
    });
    Console.WriteLine(myString);
    return myString;
}

private void button1_Click(object sender, EventArgs e)
{
    DoStuff();

    while (true) {
        Console.WriteLine("Doing Stuff on the Main Thread...................");
        System.Threading.Thread.Sleep(100);
}

所以执行的结果是这样的: 长时间运行的操作已开始 0 1 2 …… 225 226 在主线程上做事............ 227 …… 等等……

但是,永远无法到达位于 Task.Run 之后的 DoStuff 方法中的代码。我不明白为什么。当然,如果我在 DoStuff 调用之前放置一个等待它可以工作,但是主线程被卡住等待执行。 这一切仅用于学习目的。 谢谢

编辑:正如下面的 cmets 所说,当代码是主入口程序并且它最初是在按钮单击事件中时,它有效地工作,这实际上是问题发生的地方,对于混淆感到抱歉。

【问题讨论】:

  • 我刚刚运行了您的示例并打印了“测试”。你确定这是你正在运行的代码吗?
  • 我运行了它,它运行良好; “测试”已打印 - 您确定您只是没有在所有其他控制台输出中闪烁并错过它吗?
  • 确认,确实返回了“Test”
  • 另外,Of course if I put an await in front of the DoStuff call it works but then the main thread is stuck waiting for execution. 具有误导性 - Main 将简单地返回,并且应用程序将在到达 await 时立即结束。听起来您实际上并没有运行控制台应用程序,这与您发布的代码示例所暗示的不同...
  • @Luaan 他实际上不能在 Main 中使用 await。我认为他很困惑。

标签: c# asynchronous async-await


【解决方案1】:

问题是您正在使用 button1_Click() 中唯一可用的 UI 线程。据推测,您的 UI 也被无限期冻结。

当您使用 async/await 时,继续执行 - 在您的情况下,行 Console.WriteLine(myString); - 将在与调用原始函数相同的同步上下文中继续。 p>

对于控制台应用程序,同步上下文是 TPL(任务并行库)线程池。它有多个工作线程,因此它将使用其中一个来执行延续。

在您的 GUI 应用程序案例 (WinForms/WPF) 中,同步上下文是 UI 线程。只能有一个 UI 线程,因此当您使用 while(true) 循环占用该线程时,没有其他东西可以运行 - 不是您的继续,也不是其他窗口消息,这就是您的 UI 被冻结的原因。

要对此进行测试,您可以删除 while(true) 循环,然后查看您的 UI 再次变得响应,并且继续将按预期运行。

【讨论】:

  • 完美答案非常感谢,我不知道同步上下文的重要性。
【解决方案2】:

当您使用计时器进行测试时,您会高度依赖测试系统的特性和负载。

试试这个:

static async Task<string> DoStuff()
{
    Console.WriteLine("Long running op started");
    var myString = await Task.Run(() =>
    {
        var result = "Test";
        for (int counter = 0; counter < 5000; counter++)
        {
            Console.WriteLine(counter);
        }
        return (result);
    });
    Console.WriteLine(myString);
    return myString;
}

static void Main(params string[] args)
{
    var task = DoStuff();

    while (!task.IsCompleted)
    {
        Console.WriteLine("Doing Stuff on the Main Thread...................");
    }
}

【讨论】:

  • 这段代码更好,也更有意义,但是我仍然不知道为什么我的代码不能正常工作(如果你想查看它,请查看我上面的最后一条评论)
猜你喜欢
  • 1970-01-01
  • 2020-01-03
  • 2021-10-11
  • 1970-01-01
  • 2018-12-09
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 2022-10-25
相关资源
最近更新 更多