【问题标题】:Can async / await be used for user input? [duplicate]async / await 可以用于用户输入吗? [复制]
【发布时间】:2021-08-28 19:52:23
【问题描述】:

我正在尝试在 C# 和 Unity 中使用 asyncawaitTasks 来环绕我的大脑。这是场景:

  1. 用户单击按钮。
  2. 其脚本(例如:MyScene.ButtonOnClick())会生成一个(自定义)对话框并输入等待用户响应的模式。
  3. 然后用户通过单击三个按钮之一从三个选项(例如:enum DBResponse { Yes, No, Cancel })中进行选择。
  4. 结果返回到原始按钮点击后的脚本。
  5. 原始脚本使用响应继续执行代码。

似乎asyncawaitTask<TResult>(即"Task-based Asynchronous Pattern", or TAP)将是这个问题的现代答案,而不是使用事件和侦听器或 Unity 的协程,但是只有我能找到的例子与计算量大的例程或读/写有关,而不是用户输入。

我在这里尝试使用错误的工具吗?如果没有,那么我可以在三个按钮的 OnClick() 方法中添加什么来让用户对原始脚本的响应?我正在努力标记一个正在进行的异步,即有一个更新并且它已经完全可以继续进行(这听起来很像监听一个事件,这对我来说也是一个弱点)。

在早期,我会使用静态事件管理器以及一系列侦听器和调用器作为触发器。最近,我使用了一个协程,但因为它没有返回值,所以我将响应存储为公共静态值,这似乎非常错误。

这似乎是一个如此简单而根本的问题,但我还没有能够破解它。我有一种感觉,如果这个正确的工具,那么我缺少Task的方法和属性的一些基本用法。

额外阅读的指针会很有帮助!

【问题讨论】:

  • 您的“等待模式”具体涉及什么?
  • 另外,我注意到 Unity 有自己的特点 w.r.t.协程(例如,多年来一直 (ab) 使用 yield return + IEnumerable<T> 协程,这不是完全它的用途) - 所以我想知道这是否也会让你失望关闭。
  • 我重新打开了这个问题,因为标记的欺骗不适用于 Unity,并且 Unity 与普通 .NET 环境不同足以证明它自己的问题。
  • @Dai Holding 模式仅仅意味着阻止一个方法(例如原始的 ButtonOnClick() 方法)向前移动,直到确定结果。目前,它调用 StartCoroutine(WaitForThingToFinishThenRunThis(TheRestOfTheOperation))。
  • 你能用StartCoroutine发布一个完整的例子吗?另外,要确认一下,您是在问什么时候专门为 Unity 编写代码,还是笼统地问?

标签: c# unity3d


【解决方案1】:

似乎 async、await 和 Task(即“基于任务的异步模式”或 TAP )将是这个问题的现代答案

这是在欺骗你。虽然看起来这将是一个很好的用例,但事实并非如此。使用 async/await 模式的主要优点是使通常等待 IO 结果(网络、硬盘驱动器等)的线程返回可用于其他任务。这不是那种情况。

我强烈建议观看 Lucian Wischik 包装 event to expose async/await

Lucian Wischik 曾经/现在在 Microsoft 的 VB/C# 语言设计团队工作,并且在发布时是 Microsoft 在 async/await 方面知识最渊博的人之一。

所以这是一个非常粗略的示例,说明如何包装事件以供等待消费。看了之后,你可以决定它是否更容易阅读和更容易维护,而不是直接使用事件。

public async Task<DBResponse> ShowDialogAsync() 
{
  var tcs = new TaskCompletionSource<DBResponse>();
  EventHandler<object> lamda = (s,e) => tsc.TrySetResult(MyDialog.Result);

  try 
  {
    MyDialog.OnClose += lambda;
    MyDialog.Show();
    var result = await tcs.Task;
    return result;
  }
  finally
  {
    MyDialog.OnClose += lambda;
  }
}

所以绝对清楚,这并没有提供您在问题中建议的替代,因为它仍在使用事件。

似乎 async、await 和 Task(即“基于任务的异步模式”或 TAP )将是解决这个问题的现代答案,而不是使用事件

【讨论】:

  • 是什么让您认为在等待 IO 的同时允许线程执行其他工作直到完成不是一个好主意?
  • @Blindy 这种屈尊俯就是不必要的。 .NET 中的一流异步在实践中都是关于 IO 的! Task&lt;T&gt; 和 TPL 确实早于 async,但使用协程减少/消除被 IO 阻塞的线程的想法正是为什么它对现代开发来说很重要。每个线程默认占用1-4MB。
  • @Servy 我从来没有说过await 会阻塞线程,也没有说过阻塞线程是个好主意(通常)。
  • @Blindy 观察到async/await 是自 VS2010 以来 C# 中的一流语言功能(尽管我承认术语“一流”是主观的)。如果您查看SynchronizationContext 等的源代码,“并且异步与线程无关”显然是不真实的。但主要是async 的官方文档用线程来描述它:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
  • @Dai You 说的是 .Net,而不是 C#。坚持真理。而SynchronizationContext 仍然与线程无关,您可以(并且确实)构建单线程同步上下文。事实上,在这种特定情况下,这正是您所需要的。
猜你喜欢
  • 2016-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多