如何从另一个方法调用异步方法
Posted
技术标签:
【中文标题】如何从另一个方法调用异步方法【英文标题】:How to call an async method from another method 【发布时间】:2017-04-27 14:21:16 【问题描述】:我很难从当前方法调用异步方法。 尝试做这样的事情:
int i;
public void Method1()
while (statement1)
~code~
Method2(i);
while (statement2)
~code~
Method2(i);
public async void Method2(int i)
if(statement)
~code~
await Task.Delay(2000);
else
~code~
await Task.Delay(2000);
所以我基本上希望Method2
成为一种控制流程的方法(使用另一种更改图片框中图片的方法),但我无法让它工作,当它工作时它不会延迟任何事情。有谁知道我做错了什么?
Method2
最终会更改 Method1
的 while 语句。
【问题讨论】:
a) Method1 是否必须等待 Method2 完成才能继续执行? b) 你也可以让 Method1 异步吗? c) 不要使用 async void,使用 async Task 请发帖 minimal reproducible example - “Method2 最终会更改 Method1 的 while 语句”不足以了解发生了什么。async
并不意味着“在后台执行”。它的意思是“给我一个承诺,以后我可以await
”(并做一些其他的事情)。根据您要实现的具体目标,可以使用多种方法来重写它。为什么要再次以 Method2
async 开头?
a) 是的,这正是我想要的。 Method2 修改 while 语句中的两个变量之一,完成后 Method1 继续到第二个 while。
【参考方案1】:
async/await 的 best practice 是“一直使用”异步(除非您真的不关心 Method1 等待 Method2 完成)。
可以将 Task.Wait(或类似结构)与异步代码混合使用,但它是 bad idea,因为它可能导致死锁。
正如其他人所指出的那样,最好的办法是让 Method1 也异步:
public async Task Method1()
while (statement1)
await Method2(i);
// ...
请注意,您还必须让 Method1 返回一个 Task,否则您将等不及:
public async Task Method2
这可能是XY Problem 的情况,因为您提供的代码示例首先没有理由是异步的(或者甚至是单独的方法) - 您只需执行 Thread.Sleep反而。此外,“if”语句毫无意义,因为根据您向我们展示的内容,无论哪种方式,您都会延迟 2 秒。如果您可以展示更丰富的代码示例,这将很有帮助,这样我们可以更好地了解您正在尝试做什么,因此我们可以在此处推荐 async 是否甚至是合适的解决方案。
最后一点:async/await 的目的之一是允许调用线程在等待结果时执行其他工作 - 例如,如果您想在不“挂起” UI 的情况下下载文件。我已经看到很多情况,人们使用 async/await 的方式基本上消除了目的。例如:
static void Main(string[] args)
// This is a terrible thing to do but it's for illustration purposes
Task task = Method1();
task.Wait();
// Some other work
private static async Task Method1()
await Method2();
// Some other work
private static async Task Method2()
await Method3();
// Some other work
private static async Task Method3()
await Task.Delay(1000);
这是一个非常愚蠢的说明,当然,但在这种情况下,异步/等待完全没有意义,因为它只是按顺序执行每个操作。
【讨论】:
正如我所说,Method2 用于动画和图片框之间的更改。无论哪种方式我都想要延迟,但是更改图片的“方式”是由方法 2 中的 if 定义的,并且那里的代码太多,我不想让你们感到困惑。虽然无法理解反对票。 @supItsMe 我没有投反对票,但为了清楚起见,将这些信息放在问题本身中可能会有所帮助(因为从原始问题中不清楚你为什么在首先;最好在问题本身中包含对您要完成的任务的某种描述)。【参考方案2】:对于另一个能够等待 Method2 的方法,后者必须返回具有 Task 或 Task 的返回类型(而不是 void):
public async Task Method2(int i)
if(statement)
~code~
await Task.Delay(2000);
else
~code~
await Task.Delay(2000);
Method1 应该被标记为 async 并等待 Method2:
public async void Method1()
while (statement1)
~code~
await Method2(i);
while (statement2)
~code~
await Method2(i);
【讨论】:
【参考方案3】:您应该使Method1
也异步并为Method2
调用添加等待运算符:
public async Task Method1()
while (statement1)
~code~
await Method2(i);
while (statement2)
~code~
await Method2(i);
public async Task Method2(int i)
if(statement)
~code~
await Task.Delay(2000);
else
~code~
await Task.Delay(2000);
如果您出于某种原因需要 Method1 同步,您应该在 Method2 返回的任务上调用 Wait()。但是,这被认为是不好的做法,因为您失去了 .NET 线程池的优势。
【讨论】:
“不能等待 void 方法”。 将 Method2() 的返回类型更改为 Task: public async Task Method2(int i) 我是否必须在 Method2 中返回某些内容才能让 Method1 继续执行?另外,我可以在 Method2 中修改全局数据吗? @supItsMe 您必须在方法签名中将返回类型声明为 Task 但您不必在任何时候都有明确的返回语句 - 编译器会在后台执行一些“魔术”来为你处理好。 是可以从异步方法修改外部状态,但你必须小心如何避免竞争条件。以上是关于如何从另一个方法调用异步方法的主要内容,如果未能解决你的问题,请参考以下文章