C# 如何实现返回任务的接口方法<;T>;?
我有一个接口C# 如何实现返回任务的接口方法<;T>;?,c#,.net,asynchronous,task-parallel-library,async-await,C#,.net,Asynchronous,Task Parallel Library,Async Await,我有一个接口 interface IFoo { Task<Bar> CreateBarAsync(); } 但是我应该如何实现类Foo2,该类使用同步方法来创建Bar 我可以实现同步运行的方法: async Task<Bar> CreateBarAsync() { return SynchronousBarCreator(); } 从性能的角度来看,我认为两种方法的开销大致相同,或者 我应该选择哪种方法;同步地实现async方法,或者显式地将同
interface IFoo
{
Task<Bar> CreateBarAsync();
}
但是我应该如何实现类Foo2
,该类使用同步方法来创建Bar
我可以实现同步运行的方法:
async Task<Bar> CreateBarAsync()
{
return SynchronousBarCreator();
}
从性能的角度来看,我认为两种方法的开销大致相同,或者
我应该选择哪种方法;同步地实现async
方法,或者显式地将同步方法调用包装到任务中
编辑
我正在处理的项目实际上是一个.NET4项目,具有来自NuGet包的异步/等待扩展。在.NET4上,Task.Run
可以替换为TaskEx.Run
。我有意识地在上面的例子中使用了.NET 4.5方法,希望使主要问题更加清楚。试试这个:
class Foo2 : IFoo
{
public Task<Bar> CreateBarAsync()
{
return Task.FromResult<Bar>(SynchronousBarCreator());
}
}
class Foo2:IFoo
{
公共任务CreateBarAsync()
{
返回Task.FromResult(SynchronousBarCreator());
}
}
使用提供的值创建指定类型的已完成任务。如果使用.NET 4.0,则可以使用
TaskCompletionSource
:
Task CreateBarAsync()
{
var tcs=new TaskCompletionSource();
SetResult(SynchronousBarCreator());
返回tcs.Task
}
最终,如果您的方法没有什么异步的话,您应该考虑暴露一个同步端点(<代码> CREATABAR < /代码>),它创建了一个新的<代码>栏<代码>。这样就不会有任何意外,也不需要使用冗余的
任务
当您必须从接口实现异步方法并且实现是同步的时,您可以使用Ned的解决方案:
public Task<Bar> CreateBarAsync()
{
return Task.FromResult<Bar>(SynchronousBarCreator());
}
public任务CreateBarAsync()
{
返回Task.FromResult(SynchronousBarCreator());
}
使用此解决方案,该方法看起来是异步的,但却是同步的
或者您提出的解决方案:
Task<Bar> CreateBarAsync()
{
return Task.Run(() => SynchronousBarCreator());
}
Task CreateBarAsync()
{
返回任务。运行(()=>SynchronousBarCreator());
}
这样,该方法是真正异步的
您没有一个通用的解决方案可以匹配“如何实现返回任务的接口方法”的所有情况。这取决于上下文:您的实现是否足够快,因此在另一个线程上调用它是无用的?调用此方法时如何使用此接口(它会冻结应用程序)?甚至可以在另一个线程中调用您的实现吗?为了补充其他答案,还有一个选项,我相信它也适用于.NET 4.0:
class Foo2 : IFoo
{
public Task<Bar> CreateBarAsync()
{
var task = new Task<Bar>(() => SynchronousBarCreator());
task.RunSynchronously();
return task;
}
}
在这种情况下,我相信
Task.FromResult(SynchronousBarCreator())
比Task.Run(…)
更好,因为它实际上并没有计划和运行任务来获得结果。SynchronousBarCreator
是否长期运行?它是CPU受限,还是花时间等待其他东西?在我现在正在处理的情况下,它不会长时间运行。但在未来的场景中可能会出现这种情况。这非常令人困惑,而且不是最佳实践。我的建议是:创建一个同时具有同步和异步方法的接口。这种方法的一个很好的例子是WebClient、EF等,。。。或者创建两个接口,一个用于同步,另一个用于异步方法。非常感谢,Ned,对于我的场景来说,这似乎是一个非常好的解决方案。我还在寻找一个可以在.NET4上使用异步扩展的解决方案,幸运的是,TaskEx
类还包含一个FromResult
方法。总而言之,我对这个解决方案非常满意。很高兴我能帮助大家。嘿,为什么你会给这个答案打分?此方法同步运行,但具有异步后缀并返回任务,这一点都不正确。您应该返回Task.Run(SynchronousBarCreator)以使其异步。+1为了支持此答案,我检查了Microsoft对其MemoryStream.ReadAsync所做的操作,这正是他们所使用的。看见把它添加到你已经很好的答案中可能会很有用:)非常感谢,尤瓦尔,也很高兴知道。如果没有来自Microsoft async NuGet包的异步扩展,这甚至可以工作,对吗?然而,我确实在.NET 4项目中包含了异步扩展,然后,TaskEx.FromResult
方法似乎是更吸引人的方法。是的,您可以使用它而无需任何扩展Task.FromResult
和TaskEx.FromResult
只是TaskCompletionSource
的一个包装,可以链接任务。运行(或等待任务。延迟,或使用ContinueWith),如果这个方法将来是异步的-现在不异步执行它可能会创建不可预知的执行顺序或导致竞争条件。您是否会推荐我的第一个实现(async Task CreateBarAsync(){return SynchronousBarCreator();}
),或者这种方法永远不可取?您不应该使用任务。Run
几乎总是被过度使用。真正使用它的原因只有一个,那就是当您在GUI应用程序上进行计算时。但是很少有计算(相对于CPU)密集型任务。@Aron我同意它经常被过度使用。当您必须调用同步的第三方库时,即使它执行本可以异步完成的耗时任务,它也会很有用。非常高兴知道,非常感谢您提供这些附加信息!如果在等待异步方法之前抛出异常,则该异常将被抛出到同一堆栈上或同时存储?@Guillaume,是的,该异常也将被存储,即使是从async
方法的同步部分抛出。
public Task<Bar> CreateBarAsync()
{
return Task.FromResult<Bar>(SynchronousBarCreator());
}
Task<Bar> CreateBarAsync()
{
return Task.Run(() => SynchronousBarCreator());
}
class Foo2 : IFoo
{
public Task<Bar> CreateBarAsync()
{
var task = new Task<Bar>(() => SynchronousBarCreator());
task.RunSynchronously();
return task;
}
}
interface IFoo
{
Task<Bar> CreateBarAsync(CancellationToken token);
}
class Foo2 : IFoo
{
public Task<Bar> CreateBarAsync(CancellationToken token)
{
var task = new Task<Bar>(() => SynchronousBarCreator(), token);
task.RunSynchronously();
return task;
}
}