C# 嵌套异步方法

3
这样做可能吗?还是说这样做很危险/不好?如果不好的话,还有其他方法可以解决吗?
void methodA () 
{
    while (something) {
        // do stuff
        methodB();
    }
}

async Task methodB() 
{
     bool b = await methodC();
     // do something with b
}

async Task<bool> methodC() 
{
    await Task.Delay(1000);
}

我尝试实现的是让methodAmethodC等待IO时能够执行其他任务。因此,我希望methodC在繁忙时返回到methodB,而由于methodB等待答案,它将返回到methodA,在那里methodA可以继续处理其他任务,并可能再次调用methodB

something是什么,为什么你没有等待调用methodB的结果? - Justin Niessner
这不仅不错,而且这正是异步编程的全部意义。毕竟,Task.Delay只是在另一个方法中等待的方法(或者换句话说,Task.Delay并没有什么你作为C#程序员不能做的事情)。这并不是说你不能犯错误...异步编程是另一层复杂性。 - NPSF3000
@JustinNiessner 我们有一个线程在循环中等待新消息,一旦接收到消息,它将处理一些内容并将其发送到服务器(异步调用,因此需要使用task.delay)。我想知道这种编程方式是否可行,而不会引入任何糟糕的东西(例如死锁)。 - Svet Angelov
2个回答

0

是的,这是标准做法。

async Task methodA()
{
    while (something)
    {
        Task b = methodB();
        // do stuff
        await b;
    }
}

需要注意的是,这里引入了并发性,因此您需要确保在 A 执行时不会出现任何线程问题而 B 正在执行。


他们将在不同的数据上工作。只是目前我们正在使用 Task.Run,但由于我们正在进行IO工作,因此我觉得使用异步/等待可能更合适。这听起来合理吗? - Svet Angelov
不确定你的代码和仅使用 await methodB(); 有什么区别。他没有在任何地方使用 b。在他的示例中,b是布尔值,在你的示例中是任务。"Do stuff"将在此处阻塞循环。为什么会得到赞?EJoshuaS的答案是正确的。 - MistyK

0

在MethodA中不等待MethodB完成可能是完全可以接受的(只要你在MethodA中不需要MethodB完成才能做其他事情,并且小心避免竞争条件)。不过还有一些其他选项。

你可能想看看Task.ContinueWith

这里我非常喜欢的第二个选项:

List<Task> tasks = new List<Task>();
while (something) {
        // do stuff
        // This doesn't actually wait for methodB - it just keeps going
        Task methodBTask = methodB();
        tasks.Add(methodBTask);
    }

// Wait for all of the tasks we started to complete
await Task.WhenAll(tasks);
// ...

我认为这应该可以做到你想要的,并且不容易出现竞态条件。基本上,这将在 MethodB 中启动任何操作,无论你想要多少次,然后等待所有操作完成一次它们都被“排队”。


抱歉,我打错字了,我确实想调用 methodC,但我并不想在 methodA 中等待 methodB,事实上,我希望 methodA 能够再次调用 methodB,即使另一个对 methodB 的调用尚未完成。 - Svet Angelov
@SvetAngelov 我进行了编辑。我认为我的新样本应该完全符合你的要求。 - EJoshuaS - Stand with Ukraine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接