【问题标题】:async await blocking, what is wrong?异步等待阻塞,有什么问题?
【发布时间】:2016-03-08 22:31:30
【问题描述】:

我正在尝试测试 .NET 的异步/等待功能。我在 LinqPad 中设置了一个小测试:

void Main(string[] args)
{
    Test.DoStuff().Wait();
}

// Define other methods and classes here
public class Test
{
    public async static Task DoStuff()
    {
        string s1 = "Hello 1";
        string s2 = "Hello 2";
        var s3 = await Test.Gimme();
        string s4 = "Hello 4";

        Console.WriteLine(s1);
        Console.WriteLine(s2);
        Console.WriteLine(s3);
        Console.WriteLine(s4);
    }

    public async static Task<string> Gimme()
    {
        return await Task.Run<string>(() => RetString());
    }

    public static string RetString()
    {
        Console.WriteLine("Begin");

        for (int i = 0; i < 90000000; i++)
        {
            string s = "FOO";
            s = s + s;
            s = s + s;
        }

        Console.WriteLine("End");
        return "Task Hello 3!";
    }
}

据我了解,我认为代码会一直执行到 s3 再次被使用 => Console.WriteLine(s3);

我错过了什么?!我认为 await 关键字可以做到这一点,只要不使用等待的结果,程序就会继续做它的事情。

也许我执行任务错了?!

【问题讨论】:

  • await 将等待等待的对象完成,具体如何完成取决于上下文,但这意味着 string s4 = ...Test.Gimme 完成之前不会执行。
  • 如果您想实现想要的行为,请致电Console.WriteLine(await s3);。这将在打印 s1s2 之前开始执行 Gimme()。
  • 如果你想模拟工作而不实际编写一个计算无用suff的循环,只需等待Task.Delay。
  • 我对你的代码感到困惑。 return await Task.Run... 超过 return Task,Run,,, 有什么意义?当你可以说“我的任务是做三明治”时,你会说“我的任务是等待完成制作三明治的任务”,这对我来说似乎很奇怪。
  • 没有等待我得到一个同步方法(编译器警告)。

标签: c# .net async-await


【解决方案1】:

我认为 await 关键字可以做到这一点,只要不使用等待的结果,程序就会继续执行它的工作。

你错了。 await 关键字将等待该操作。也就是说,关键字等待该任务的result,而不是返回可能在稍后完成操作的Task。 (在这种情况下是一个字符串。)

所以当你这样做时:

var s3 = await Test.Gimme();
string s4 = "Hello 4";

直到async 操作的结果可用时,第二行才会执行。与此相反:

var s3 = Test.Gimme();
string s4 = "Hello 4";

哪个等待操作完成,而只是在s3 中放置对Task&lt;string&gt; 的引用,这可能会在稍后完成(等待)。 p>

这里的想法是DoStuff() 方法本身 将按照命令式编写的顺序执行代码,就像任何其他代码一样。但是该代码调用的东西可能是异步的,因此反过来调用DoStuff()的代码可以选择以异步方式处理它。

大多数async 方法在逻辑上是同步的,但封装了底层异步操作并将选项公开给更高级别,以免阻塞这些操作。秉承“一直异步”的口号,许多此类方法提供“传递异步”,并允许顶层 UI 异步处理底层 I/O。

【讨论】:

  • 谢谢,一个大细节,完全搞错了。现在我想知道为什么 LinqPad 在控制台中放置“等待...”并稍后替换它...
  • 我知道它正在这样做是因为它被延迟了......猜想这是一个不错的 LinqPad 功能。
【解决方案2】:

我错过了什么?!我认为 await 关键字可以做到这一点,只要不使用等待的结果,程序就会继续做它的事情。

你是对的;您的困惑是“做事”的意思。在等待结果时完成的“东西”是 DoStuff 的 caller 的“东西”,即 Main。当 DoStuff 因为任务未完成而无法取得进展时,调用者会做什么? 它调用等待。这就是发生的事情!

您说您想等待结果,这意味着您希望调用者在异步处理任务时执行它所做的任何事情。调用者说“我除了同步等待之外无事可做*。如果调用者在调用 Wait 任务之前做了一些其他工作,那么你会看到这项工作正在完成。

【讨论】:

  • 该死的......你是对的,我猜我把它弄混了。谢谢!
【解决方案3】:

如果完全完成,Await 实际上会一直执行直到该过程。因此,您的测试方法应该完全构建整个 RetString,然后将其返回给 Gimme,然后 Gimme 会将字符串返回给 var s3,然后继续处理。

来自 Microsoft:await 运算符应用于异步方法中的任务,以暂停该方法的执行,直到等待的任务完成。任务代表正在进行的工作。在此处找到更多详细信息:https://msdn.microsoft.com/en-us/library/hh156528.aspx

【讨论】:

    猜你喜欢
    • 2019-10-16
    • 2022-01-04
    • 2016-03-13
    • 2011-04-03
    • 1970-01-01
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    相关资源
    最近更新 更多