没有等待或返回的 C# 异步任务方法

Posted

技术标签:

【中文标题】没有等待或返回的 C# 异步任务方法【英文标题】:C# Async Task Method Without Await or Return 【发布时间】:2018-04-21 14:28:02 【问题描述】:

我有一个接口 I,它在两个地方实现,例如:

interface I 
 
   Task DoSomething();

该接口具有异步任务 DoSomething 方法 API,然后在 A 类中实现,如:

class A : I ....

class B : I ....

在A类中,DoSomething的实现如下,没关系:

public async Task DoSomething()

    if (...)
    
        await DoIt();
    

但是,在 B 类中,DoSomething() 的实现不应该做任何事情。 所以,它的实现是这样的:

public async Task DoSomething()

    // nothing

这可以编译,但我不确定它做这样的事情有多正确,除了该方法没用。

但是在这种情况下“无用”在这种情况下是可以的,因为实现它只是因为实现接口 I 的类 B 需要它。

我想知道这是否是实现返回异步任务但没有等待或返回的方法的正确方法?我知道这个方法不会做任何事情并同步执行,因为没有调用等待。

更新:在 SO 上已经提出了类似的问题,在问这个问题之前我已经检查了所有这些问题。没有人问我在问什么

【问题讨论】:

如果您打算在其中使用await(直接),您只需将方法标记为async。它返回Task这一事实足以满足接口; async/await 与接口无关。 【参考方案1】:
public Task DoSomething()

    return Task.CompletedTask;

不需要async

如果您使用的是旧版本的 .NET,请使用以下代码:

public Task DoSomething()

    return Task.FromResult(0);

如果你发现你需要返回一个结果但你仍然不需要await 任何东西,试试;

public Task<Result> DoSomething()

    return Task.FromResult(new Result())

或者,如果你真的想使用异步(不推荐);

public async Task<Result> DoSomething()

    return new Result();

【讨论】:

我知道不推荐第四个选项,但你没有给出原因? @m3z - 编译器将根据“异步方法缺少等待运算符并将同步运行”的行生成警告。更重要的是,编译器将生成一个完整的IAsyncStateMachine,否则这是一个非常简单的方法。智能编译器可能会对此进行优化,但从对sharplab.io 的简短访问来看,似乎很有可能不会,并且在 NET47x 上,它 JIT 对 259 字节的 x86 程序集进行异步方法与 71 字节的同步。 有道理。谢谢 No need for the async - 但它有害吗?我有点想用return Task.ComletedTask; 行换成async 关键字,如果它没有任何危害的话.. @vegar- 正如 sellotape 所提到的,异步方法有与之相关的开销,并且只能用于实现 I/O 密集型的东西(比如写入文件、进行外部 Http 调用) .对于简单的方法或“计算密集型”的方法(例如添加两个数字,计算 10^10 的阶乘),异步没有帮助,因此不需要创建额外的额外状态开销。【参考方案2】:

我发现大多数人都喜欢省略 async 而使用 Task.ComletedTask。但是即使不使用await,在异常处理上还是有很大区别的

考虑以下示例

static async Task Main(string[] args)


    Task task = test(); // Will throw exception here
    await task;

    Task taskAsync = testWithAsync();
    await taskAsync; // Will throw exception here


static Task test()

    throw new Exception();
    return Task.CompletedTask; //Unreachable, but left in for the example


static async Task testWithAsync()

    throw new Exception();

使用

test().ContinueWith(...);Task.WhenAll(test())

可能会导致意外行为。

因此,我更喜欢async 而不是Task.CompletedTaskTask.FromResult

【讨论】:

以上是关于没有等待或返回的 C# 异步任务方法的主要内容,如果未能解决你的问题,请参考以下文章

C# 理解阻塞 UI 和异步/等待与 Task.Run 的问题?

异步等待返回任务

异步/等待和任务

shell 异步任务模拟多线程

[C#] 走进异步编程的世界 - 剖析异步方法(下)

如果我不关心它的返回值,我应该等待一个“异步任务”函数吗? [复制]