等待多个可选任务

3

你好,我想知道是否有更简洁的方法来编写下面的异步代码。基本上,我想等待所有任务完成,但其中一个任务是可选的。感觉这样做过于繁琐,考虑通过某些回调来实现,但一直没有想出来。

var mobile = true;

var task1 = _service.Async1();
var tasks = new List<Task>
{
    task1
};

Task<int> task2 = null;
if (!mobile)
{
    task2 = _service.Async2();
    tasks.Add(task2);
}

await Task.WhenAll(tasks);

var result1 = task1.Result;

if (!mobile)
{
    result2 = task2.Result;
    // Do stuff
}

你需要result1来处理result2吗(在代码中看到"// Do stuff")?例如,"stuff"是否使用了result1 - spender
您可以在移动案例中替换一个虚假的预先完成任务。 var results = Task.WaitAll<int>(_service.Async1(), mobile ?Task<int>.FromResult(0) : _service.Async2()); 现在,如果调用了Async2(),则results[1]包含其结果;否则为零,而results[0]包含Async1()的结果。 - Raymond Chen
@spender 在这种情况下不是这样的。 - JuhaKangas
@RaymondChen 嗯,我之前也尝试过类似的方法,但我并不是很喜欢那种方式。 - JuhaKangas
1个回答

5

没有必要创建一个列表并一次性等待所有结果。为什么不在需要时 await 呢?如果 task2 运行时间比 task1 更长,你可以至少在 task2 完成之前开始处理它。

像这样:

var task1 = _service.Async1();

Task<int> task2 = null;
if (!mobile)
{
    task2 = _service.Async2();
}

var result1 = await task1;

if (!mobile)
{
    var result2 = await task2;
    // Do stuff
}

2
你的代码有一个行为改变,我刚刚意识到。如果 task2 抛出异常,并且 mobiletrue,OP 的代码会从 Task.WhenAll 中引发异常,而你的代码则会让异常未被观察到。这样做没有问题,只是行为上的改变,OP 应该注意到这一点。它还允许你在保持 task2 运行的同时离开代码块的作用域。如果稍后出现 _service.Async3(),并且要求在它启动时没有其他操作正在运行,这也可能导致问题。同样地,没有错,只是需要注意副作用。 - Scott Chamberlain
1
@JonHanna 为什么?我没有看到在启动 task2 的调用之前等待 task1。 - spender
1
@JonHanna 什么?不,那不是 await 的工作方式。await 不会启动任务,这就是异步方法本身的工作。 - Luaan
不好意思,我刚才看错了顺序。请忽略我之前的评论。 - Jon Hanna
啊,当然,谢谢!我一直在使用WhenAll上纠结。在实际代码中我仍会使用它,但是会将可选任务分离出来并单独等待。 - JuhaKangas
@ScottChamberlain 感谢您的提醒! - JuhaKangas

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