如何从另一个方法调用异步方法

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 但您不必在任何时候都有明确的返回语句 - 编译器会在后台执行一些“魔术”来为你处理好。 可以从异步方法修改外部状态,但你必须小心如何避免竞争条件。

以上是关于如何从另一个方法调用异步方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使用参数从另一个方法调用方法

静态方法 - 如何从另一个方法调用一个方法?

如何从另一个类调用@selector 方法

如何从另一个类调用执行 segue 方法?

如何从另一个方法调用指向方法的指针

如何从另一个类调用方法函数?