我最近一直在学习异步编程,我想我已经掌握了它。异步编程很简单,只允许我们的程序进行多任务处理。
混淆伴随着await
和async
的编程,它似乎让我更加困惑,有人可以帮助回答我的一些担忧吗?
我没有及时看到async
关键字,只是你想让某个方法让Visual Studio知道该方法可以await
并让你发出警告的方法您。如果它有一些其他特殊含义实际影响某些东西,有人可以解释一下吗?
转到await
,在与朋友交谈后,我被告知我有一件大事是错的,await
没有阻止当前的方法,它只是执行该方法中剩下的代码并在自己的时间进行异步操作。
现在,我不确定这种情况经常发生,但是我们可以说你有这样的代码。
Console.WriteLine("Started checking a players data.");
var player = await GetPlayerAsync();
foreach (var uPlayer in Players.Values) {
uPlayer.SendMessage("Checking another players data");
}
if (player.Username == "SomeUsername") {
ExecuteSomeOperation();
}
Console.WriteLine("Finished checking a players data.");
正如您所看到的,我在GetPlayerAsync
上运行了一些异步代码,如果我们深入了解范围并且我们需要访问播放器会发生什么,但它还没有返回播放器?
如果它没有阻止该方法,它如何知道该玩家不是空的,它是否会做一些魔法并等待我们如果我们到达那种情况,或者我们只是禁止自己以这种方式写作方法并自己处理。
答案 0 :(得分:13)
我最近一直在学习异步编程,我想我已经掌握了它。
我是该功能的设计师之一,我不觉得我甚至接近掌握它,你问的是初级问题并且有一些非常非常错误的想法,所以我怀疑在这里发生了一些狂妄自大。
异步编程只是让我们的程序进行多任务处理。
假设你问过"为什么有些物质很硬而有些软?"我回答说,物质是由原子排列组成的,有些原子排列很硬,有些是柔软的。虽然这无疑是正确的,但我希望你能够继续这种无益的不解释。
同样,你刚刚取代了模糊的词语"异步"另一个模糊的词"多任务"。这是一个没有解释的解释,因为您还没有明确定义多任务的含义。
异步工作流程无疑是关于执行多个任务的。 这就是为什么工作流中的基本工作单元是Task<T>
monad。异步工作流是通过构建它们之间的依赖关系图来组成多个任务。但这并没有说明如何在软件中实现该工作流程。这是一个复杂而深刻的主题。
我没有太多地看到async关键字,只是你想方法让Visual Studio知道该方法可能等待某些事情并允许它警告你。
这基本上是正确的,但并不认为它是在告诉Visual Studio; VS并不在乎。它是你所说的C#编译器。
如果它有一些其他特殊含义实际影响某些东西,有人可以解释一下吗?
它只是使await
成为方法内的关键字,并对返回类型设置限制,并将return
的含义更改为&#34;表示与此调用关联的任务已完成& #34;,以及其他一些家政细节。
await不会阻止当前的方法
当然可以。为什么你会认为它没有?
它不会阻止线程,但它肯定会阻止方法。
它只是执行该方法中剩下的代码,并在自己的时间内执行异步操作。
绝对不是。这完全是倒退。 await
执行相反的。 Await表示如果任务未完成,则返回给您的调用者,并注册此方法的其余部分作为任务的继续。
正如您所看到的,我在GetPlayerAsync上运行了一些异步代码,如果我们深入了解范围并且我们需要访问播放器会发生什么,但它还没有返回播放器?
这不会发生。
如果在player
执行时分配给await
的值不可用,则await 返回,方法的其余部分恢复当值可用时(或任务异常完成时)。
请记住,等待意味着异步等待,这就是为什么我们称之为&#34; await&#34;。 await是异步工作流中的一个点,在等待任务完成之前工作流无法继续。这就是你描述等待的相反。
同样,请记住异步工作流是什么:它是一组任务,其中这些任务彼此依赖。 我们通过在依赖点处放置await
来表示一个任务依赖于另一个任务的完成。
让我们更详细地了解您的工作流程:
var player = await GetPlayerAsync();
foreach (var uPlayer in Players.Values) ...
if (player.Username == "SomeUsername") ...
等待意味着&#34;此工作流程的其余部分无法继续,直到获得玩家&#34;。这实际上是对的吗?如果您想要在获取播放器之前执行foreach
而不是,那么这是正确的。但是foreach并不依赖于玩家,因此我们可以这样重写:
Task<Player> playerTask = GetPlayerAsync();
foreach (var uPlayer in Players.Values) ...
Player player = await playerTask;
if (player.Username == "SomeUsername") ...
请参阅,我们将依赖点移至工作流程的后期。我们开始了#34;获得一名玩家&#34;任务,然后我们做foreach,然后我们在需要之前检查播放器是否可用 。
如果你相信await
某种方式&#34;接听电话并使其异步&#34;,这应该消除这种信念。 await
执行任务,如果不完整则返回。如果完成,则提取该任务的值并继续。 &#34;获得一名玩家&#34;操作已经异步,await
没有这样做。
如果它没有阻止该方法,它如何知道该玩家不为空
阻止该方法,或者更确切地说,它暂停方法。
该方法暂停,直到任务完成并且提取值后才会恢复。
它不会阻止线程。它返回,以便调用者可以继续在不同的工作流中继续工作。任务完成后,将继续安排到当前上下文,方法将恢复。
答案 1 :(得分:3)
await
不会阻止当前的方法
正确。
它只是执行该方法中剩下的代码,并在自己的时间内执行异步操作。
不,一点也不。它调度方法的其余部分以在异步操作完成时运行。它不会立即运行该方法的其余部分。在等待操作完成之前,不允许允许运行方法中的任何其余代码。它只是不阻塞进程中的当前线程,当前线程返回给调用者,并且可以继续执行它想做的任何事情。当异步操作完成时,方法的其余部分将由同步上下文(或线程池,如果不存在)调度。
答案 2 :(得分:1)
我有一个主要的错误,await不会阻止当前方法,它只是执行该方法中剩下的代码并在其自己的时间内执行异步操作。
但 阻止该方法,因为调用await
的方法在结果出现之前不会继续。它只是不会阻塞该线程方法正在运行。
...我们需要访问播放器,但它还没有返回播放器吗?
这根本就不会发生。
async / await非常适合执行各种I / O(文件,网络,数据库,UI),而不会浪费大量线程。线程很贵。
但作为一名程序员,你可以编写(并思考),好像它是全部同步发生的。
答案 3 :(得分:-4)
在此代码中,您将不使用Await,因为GetPlayerAsync()
运行一些异步代码。您可以从Async和Await不同的角度考虑它,“Async”正在等待,而“Await”是异步操作。
尝试使用Task< T >
作为返回数据。