【问题标题】:How to know my async method is being awaited?如何知道我的异步方法正在等待?
【发布时间】:2015-07-27 22:59:46
【问题描述】:

是否有可能知道我的方法是使用'await'关键字调用的吗?

例如; MyAsync() 方法想知道它是否正在等待。

public void CallForBackground()
{
    MyAsync();
}

public async void CallAsync()
{
    bool result = await MyAsync();
}

public Task<bool> MyAsync()
{
    return Task.Run(() =>
    {
    //do something endlessly if its being called without 'await', but how do I know the caller is 'await'ing or not?
    //do something only once if its being called with 'await', but how do I know the caller is 'await'ing or not?


    return true;
    });
}

已编辑:添加了一个场景,我想知道 MyAsync() 是否在有或没有“等待”的情况下被调用;

1) 假设 MyAsync() 正在使用 TCP 连接到远程服务器。

2) MyAsync() 是异步且可等待的。

3) 假设 UserA 想异步连接到远程服务器,一旦完成,他/她想在继续他的过程之前知道它是否成功。类似于 CallAsync() 方法的实现。

4) 并且 UserB 想要触发 MyAsync() 方法,而不是等待它完成。在这种情况下,用户 B 不关心它是否已连接,直到他向远程服务器发送消息。类似于 CallForBackground() 方法的实现。

所以对于 UserA(等待),MyAsync() 方法将尝试一次并返回状态。但是对于 UserB(不等待),方法将继续尝试。对于这个逻辑,MyAsync() 需要知道它是否正在等待。我们如何做到这一点?

【问题讨论】:

  • 您希望您的方法MyAsync 根据调用位置和调用方式的不同而有所不同?简单地传递 bool endlessly 参数有什么问题?
  • 你认为你为什么需要它?
  • 你永远不会用 await 调用任何东西。您正在等待一个恰好由调用返回的任务。

标签: c# async-await


【解决方案1】:
  1. 您不应该让async 方法返回void。不要那样做,除非你确定这是你需要的(但很可能你不需要!)。

  2. async 是实现细节,可让您使用awaits 以​​更轻松、更友好的方式编写方法主体,并使编译器为您准备所有必要的回调等。

  3. 你没有办法知道人们在用 Task 你回来做什么。

【讨论】:

  • 我想补充一点,告诉调用者对返回的任务做了什么也是不必要的
  • 我在几个不同的地方都听说过这个,但从未见过解释,为什么不应该从异步方法返回 void?
  • @cost,这可以帮助您解决有关async void 的问题:stackoverflow.com/a/23827505/1768303
  • @MarcinJuraszek,没有 async void 的方法 CallAsync() 仅用于说明使用 'await' 关键字调用 MyAsync()。我用一个真实的例子编辑了我的问题,我想知道 MyAsync() 是否被 await 调用。
【解决方案2】:

我们如何做到这一点?

你没有*。一个方法的行为不应该因用户对其返回值所做的不同而有所不同。如果您想拥有两种不同的行为,请在您的方法中添加 bool 参数,或者更好的是,为此使用两种不同的方法。


* 实际上有一种方法可以确定您的方法是否为awaited。但它相当复杂(它涉及使用自定义等待者而不是 Task),我认为这不是正确的解决方案。

【讨论】:

  • 我的例子不是真实场景,仅用于说明。我的问题是我们如何知道它是否被称为“等待”。我接受你的回答,因为它接近我的问题。谢谢。
【解决方案3】:

显然,您希望您的操作取决于调用过程的速度。如果调用过程真的很快,它会在您检查它是否等待之前开始等待。如果它有点慢,在你检查之前它还没有开始等待。

您确定要让您的功能依赖于调用者的速度吗?

如果您知道是否有人会开始等待您的结果不是更好吗?在这种情况下,您的流程的启动者可以使用参数指示他是否会在不久的将来等待您的回答。

如果您的流程的启动者还不知道他是否会在未来等待您的回答,那么一旦他决定不再等待您的回答,他可以使用 CancellationToken 取消您的任务。

例如: - 开始一个 10 分钟的过程。首发者认为他将开始等待,比方说五分钟。在那之前,他还有更好的事情要做。 - 在启动器开始等待之前,操作员决定停止程序。所以初学者知道他永远不会开始等待。他使用 CancellationToken 表示他永远不会等待结果。 - 该进程定期检查cancellationToken,看看是否仍然预期是否会有await。

public async Task<bool> MyAsync(CancellationToken token)
{
    return Task.Run(() =>
    {
        while (!token.IsCancellationRequested)
        {   // we can still expect that in the near future someone will await
            // act accordingly
        }
        else
        {   // we know for sure that no one will await for the result anymore
            // act accordingly
         }
    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    相关资源
    最近更新 更多