returns任务接口的同步实现
Synchronous implementation of interface that returns Task
类似于 Implementing an interface that requires a Task return type in synchronous code 虽然我很好奇我是否应该忽略我的情况生成的编译器错误。
假设我有这样的界面:
public interface IAmAwesome {
Task MakeAwesomeAsync();
}
在一些实现中,使用 async
和 await
异步完成带来了巨大的好处。这确实是界面试图允许的。
在其他情况下,也许很少见,只需要一个简单的同步方法就可以做出很棒的东西。所以让我们假设实现看起来像这样:
public class SimplyAwesome : IAmAwesome {
public async Task MakeAwesomeAsync() {
// Some really awesome stuff here...
}
}
这有效,但编译器发出警告:
This method lacks 'await' operators and will run synchronously.
Consider using the await
operator to await non-blocking API calls,
or 'await TaskEx.Run(...)' to do CPU-bound work on a background
thread.
编译器实际上是在建议这个解决方案:
public class SimplyAwesome : IAmAwesome {
public async Task MakeAwesomeAsync() {
await Task.Run(() => {
// Some really awesome stuff here, but on a BACKGROUND THREAD! WOW!
});
}
}
我的问题是 - 当我选择忽略此编译器警告时应该确定什么?在某些情况下,工作是如此简单,以至于为其生成一个线程无疑会适得其反。
如果您真的想同步完成工作,您知道您的 async
方法将始终 运行 同步,这在这种情况下是可取的,那么请务必忽略警告.如果您理解警告告诉您的内容并且认为它描述的操作是正确的,那么这不是问题。毕竟这是警告而不是错误是有原因的。
当然,另一种选择是不使用方法 async
而是简单地使用 Task.FromResult
到 return 一个已经完成的任务。它会改变错误处理语义(除非你也捕获所有异常并将它们包装到你 return 的任务中)所以至少要注意这一点。如果您确实希望通过结果 Task
传播异常,则可能值得保留方法 async
并只抑制警告。
What should determine when I choose to ignore this compiler warning?
In some cases the work is so simple that spawning a thread for it is
undeniably counter-productive.
编译器并没有说 "use Task.Run inside this method"。它只是告诉你你为他准备了一个 async
方法,在你的方法声明中添加了 async
修饰符,但你实际上并没有等待任何东西。
您可以采用三种方法:
一个。您可以忽略编译器警告,一切仍将执行。请注意,状态机生成会有轻微的开销,但您的方法调用将同步执行。如果该操作耗时并且可能导致方法执行进行阻塞调用,这可能会使使用此方法的用户感到困惑。
乙。将"Awesome"的生成分为同步接口和异步接口:
public interface MakeAwesomeAsync
{
Task MakeAwesomeAsync();
}
public interface MakeAwesome
{
void MakeAwesome();
}
C。如果操作不太耗时,您可以使用 Task.FromResult
将其简单地包装在 Task
中。在选择这个之前,我肯定会测量 运行 CPU 绑定操作需要多长时间。
正如其他人已经指出的那样,您有 3 种不同的选择,所以这是一个见仁见智的问题:
- 保留它
async
并忽略警告
- 有同步/
async
重载
- 删除
async
和 return 一个已完成的任务。
我会推荐 returning already completed task:
public class SimplyAwesome : IAmAwesome
{
public Task MakeAwesomeAsync()
{
// run synchronously
return TaskExtensions.CompletedTask;
}
}
有几个原因:
- 创建方法
async
有 轻微 创建状态机和禁用某些优化(如内联)的开销,因为编译器的 try-catch 块添加。
- 您需要处理警告,并与任何其他查看此代码的团队成员一起思考
await
在哪里。
- 标记完全同步的方法有些不协调
async
。就好像在你的代码中加入while(false){}
一样,作用是一样的,只是没有传达出方法的意思。
Servy 指出 return执行任务会改变异常处理的语义。虽然这是真的,但我认为这不是问题。
首先,大多数 async
代码调用方法并在同一位置(即 await MakeAwesomeAsync()
)等待 returned 任务,这意味着异常将在无论方法是否 async
都在同一个地方。
其次,即使是 .Net 框架的 Task-returning 方法也会同步抛出异常。以 Task.Delay
为例,其中 throws an exception directly without storing it in the returned task,因此不需要 await
引发异常的任务:
try
{
Task.Delay(-2);
}
catch (Exception e)
{
Console.WriteLine(e);
}
由于 .Net 开发人员需要 except 在 .Net 中同步遇到异常,因此他们也应该从您的代码中排除异常。
类似于 Implementing an interface that requires a Task return type in synchronous code 虽然我很好奇我是否应该忽略我的情况生成的编译器错误。
假设我有这样的界面:
public interface IAmAwesome {
Task MakeAwesomeAsync();
}
在一些实现中,使用 async
和 await
异步完成带来了巨大的好处。这确实是界面试图允许的。
在其他情况下,也许很少见,只需要一个简单的同步方法就可以做出很棒的东西。所以让我们假设实现看起来像这样:
public class SimplyAwesome : IAmAwesome {
public async Task MakeAwesomeAsync() {
// Some really awesome stuff here...
}
}
这有效,但编译器发出警告:
This method lacks 'await' operators and will run synchronously. Consider using the
await
operator to await non-blocking API calls, or 'await TaskEx.Run(...)' to do CPU-bound work on a background thread.
编译器实际上是在建议这个解决方案:
public class SimplyAwesome : IAmAwesome {
public async Task MakeAwesomeAsync() {
await Task.Run(() => {
// Some really awesome stuff here, but on a BACKGROUND THREAD! WOW!
});
}
}
我的问题是 - 当我选择忽略此编译器警告时应该确定什么?在某些情况下,工作是如此简单,以至于为其生成一个线程无疑会适得其反。
如果您真的想同步完成工作,您知道您的 async
方法将始终 运行 同步,这在这种情况下是可取的,那么请务必忽略警告.如果您理解警告告诉您的内容并且认为它描述的操作是正确的,那么这不是问题。毕竟这是警告而不是错误是有原因的。
当然,另一种选择是不使用方法 async
而是简单地使用 Task.FromResult
到 return 一个已经完成的任务。它会改变错误处理语义(除非你也捕获所有异常并将它们包装到你 return 的任务中)所以至少要注意这一点。如果您确实希望通过结果 Task
传播异常,则可能值得保留方法 async
并只抑制警告。
What should determine when I choose to ignore this compiler warning? In some cases the work is so simple that spawning a thread for it is undeniably counter-productive.
编译器并没有说 "use Task.Run inside this method"。它只是告诉你你为他准备了一个 async
方法,在你的方法声明中添加了 async
修饰符,但你实际上并没有等待任何东西。
您可以采用三种方法:
一个。您可以忽略编译器警告,一切仍将执行。请注意,状态机生成会有轻微的开销,但您的方法调用将同步执行。如果该操作耗时并且可能导致方法执行进行阻塞调用,这可能会使使用此方法的用户感到困惑。
乙。将"Awesome"的生成分为同步接口和异步接口:
public interface MakeAwesomeAsync
{
Task MakeAwesomeAsync();
}
public interface MakeAwesome
{
void MakeAwesome();
}
C。如果操作不太耗时,您可以使用 Task.FromResult
将其简单地包装在 Task
中。在选择这个之前,我肯定会测量 运行 CPU 绑定操作需要多长时间。
正如其他人已经指出的那样,您有 3 种不同的选择,所以这是一个见仁见智的问题:
- 保留它
async
并忽略警告 - 有同步/
async
重载 - 删除
async
和 return 一个已完成的任务。
我会推荐 returning already completed task:
public class SimplyAwesome : IAmAwesome
{
public Task MakeAwesomeAsync()
{
// run synchronously
return TaskExtensions.CompletedTask;
}
}
有几个原因:
- 创建方法
async
有 轻微 创建状态机和禁用某些优化(如内联)的开销,因为编译器的 try-catch 块添加。 - 您需要处理警告,并与任何其他查看此代码的团队成员一起思考
await
在哪里。 - 标记完全同步的方法有些不协调
async
。就好像在你的代码中加入while(false){}
一样,作用是一样的,只是没有传达出方法的意思。
Servy 指出 return执行任务会改变异常处理的语义。虽然这是真的,但我认为这不是问题。
首先,大多数 async
代码调用方法并在同一位置(即 await MakeAwesomeAsync()
)等待 returned 任务,这意味着异常将在无论方法是否 async
都在同一个地方。
其次,即使是 .Net 框架的 Task-returning 方法也会同步抛出异常。以 Task.Delay
为例,其中 throws an exception directly without storing it in the returned task,因此不需要 await
引发异常的任务:
try
{
Task.Delay(-2);
}
catch (Exception e)
{
Console.WriteLine(e);
}
由于 .Net 开发人员需要 except 在 .Net 中同步遇到异常,因此他们也应该从您的代码中排除异常。