【发布时间】:2021-01-07 18:21:09
【问题描述】:
假设我们有这个类 - MyClass
MyClass 具有将不同类型的列表转换为 XDocument 的方法
作为示例,我们将只看一种方法,Convert
我可以把这个方法写成:
public XDocument Convert<T>(IList<T> myList)
{
XDocument doc = new XDocument("root");
//Do some synchronous work
return doc;
}
或者我可以这样写:
public Task<XDocument> Convert<T>(IList<T> myList)
{
XDocument doc = new XDocument("root");
//Do some synchronous work
return Task.FromResult(doc);
}
现在假设我们想将其卸载到程序另一部分的任务中,而其他一些任务正在做一些工作,然后等待它们全部完成,然后再在异步方法中做一些其他工作。
我知道使用该方法的第一个版本,我可以做到:
some async method...
Task t = Task.Run(() => myClass.Convert<T>(IList<T>);
Task t2...
Task t3...
await Task.WhenAll(t, t2, t3);
但是使用第二种形式的方法,似乎可以做到更简单:
some async method...
Task t = myClass.Convert<T>(IList<T>);
Task t2...
Task t3...
await Task.WhenAll(t, t2, t3);
我的问题是:
像第二个例子那样设计方法有什么缺点吗?返回一个任务以便在代码库的其他地方作为任务运行时使用,即使它是同步的。还是这更多是关于意图?
我知道这可能被认为是一个固执己见的问题,所以在我给它足够的时间来获得一些回应之后,我可能会将它从 SO 中删除。否则,如果考虑到一个足够具体和好的问题,我会留下它。
【问题讨论】:
-
如果您不等待,则无需使用Tasks,除非您有多个实现并需要匹配一个接口。
Task.Run可以吞下错误,因此请确保在它调用的代码中处理它们。除非您从磁盘加载文档,否则我看不出在当前示例中使用这两种情况的原因。在您需要异步功能之前,我会将其保留为非任务。 Async/await 确实增加了一些额外的开销。不过,对于代码审查网站来说,这可能是一个更好的问题。 -
@ps2goat 假设我们在代码库的另一部分,在一个异步方法中,我们希望将列表转换为 XDocument 的工作转移到一个任务上,并且可能正在做一些工作一些其他任务,然后等待所有这些任务完成,然后再在该方法中执行更多操作。这是否更清楚地说明了为什么将 Convert 方法设计为返回 Task
? -
所以你认为更改方法的签名以返回
Task<T>而不是T与Task.Run方法相同吗?如果你这样做了,那你就错了。完全有可能实现具有异步合约和同步实现的行为不良的方法。一种方法不是将不完整的Task交给调用者,而是强制调用者同步完成所有工作,最后将完整的Task交还给调用者。这就是第二个Convert本质上在做的事情。 -
所有三个任务
t、t1和t2将以完成状态创建。然后组合任务Task.WhenAll(t, t2, t3)也将在创建时立即完成。简而言之,什么都不会a同步发生。当前线程将简单地一个接一个地执行所有三个Convert调用,就像Convert返回一个XDocument而不是Task<XDocument>一样。 -
@TheodorZoulias 谢谢。那是我不清楚并希望了解的部分。我想删除这篇文章,但它不会让我,因为有人在下面提供了答案。