【问题标题】:Is there a way to know if a Task is being awaited?有没有办法知道是否正在等待任务?
【发布时间】:2013-11-06 23:07:05
【问题描述】:

我有办法

public Task<Task> DoSomeWorkOnARemoteMachine()

非常描述性地,它通过以下方式在远程机器上执行一些工作:

  1. 在消息总线上排队消息,表明工作应该完成
  2. 远程代理接收消息并执行工作
  3. 工作完成,代理在消息总线上排队一条消息,表示工作已完成
  4. 调用工作的应用程序接收到工作完成的消息

之所以使用Task&lt;Task&gt;,是因为第一个Task&lt;&gt;是用于消息的排队;而内部Task 在远程机器上完成工作时完成(即当收到来自代理的消息时)。远程代理在执行工作期间捕获的任何异常都会与完成消息一起传递,并在内部 Task 完成时重新抛出。

调用这个方法我使用:

await await DoSomeWorkOnARemoteMachine();

它将等待消息排队以执行作业,以及完成作业并接收任何异常。但是,如果我对远程代理上的作业是否完成不感兴趣,我可以这样称呼它:

await DoSomeWorkOnARemoteMachine();

这不会是await 内部的Task。但是,内部的Task(它从远程代理接收消息,并重新抛出异常)仍然会在某个时候执行。我觉得这有点浪费,当我不await 获得结果时,我想避免执行它。

因此,我的问题是:Task 是否有可能“知道”它是否是 awaited,如果不是,则不执行,或者执行一些其他代码路径(例如空的 Task身体)。

我确实意识到我可以实现一些替代方案,例如传递“即发即弃”标志,或为“即发即弃”添加重载。如果我可以在不更改客户端 API 的情况下实现它,那就太好了

涉及实现这种远程工作执行的其他项目的答案也很棒!

【问题讨论】:

  • 你几乎肯定不会想要这样做,即使你可以。如果后续任务被添加到该任务中,而不是立即添加会怎样。他们现在永远不会运行,因为任务永远不会完成。将任务粘贴到数据结构或字段中,然后再添加延续实际上是相当普遍的;这将使它们全部崩溃,但在一个非常混乱且难以调试的庄园中。

标签: c# asynchronous task-parallel-library async-await


【解决方案1】:

我认为它不容易或有效地实现(使用 Task.GetAwaiter 是一个坏主意,并且无法从您的函数内部访问它,请参阅 Noseratio 的答案)。这是替代解决方案:

解决方案 n°1:Task 执行的函数参数

await DoSomeWorkOnARemoteMachine(false) //Indicates that DoSomeWork shouldn't be executed

解决方案 n°2:显式任务执行

Task t = await DoSomeWorkOnARemoteMachine() ;
t.Start(); // For example, if you want to execute the resulting Task. 
           // You can also dispatch it to an other thread, etc...

【讨论】:

  • +1,像这样的bool 参数是一种自然的方式来指示外部任务内部的逻辑不启动内部任务,而是返回Task.FromResult(或null)。
  • 必须是 Start()ed 的 Task 没有多大意义,尤其是因为这意味着它必须阻止。
【解决方案2】:

这是一个非常有趣的问题。然而,如果我理解正确,我相信这是不可能的,以你提出的方式,因为它没有意义(IMO)。让我们看看下面的模型(如果我错了请告诉我):

static async Task<Task> DoSomeWorkOnARemoteMachine()
{
    // Point X: 
    await Task.Delay(1000);
    // Point Y: 
    Console.WriteLine("request sent");
    var taskInner = Task.Delay(2000);
    // Point A: here you want to know if there's an await at Point B
    return taskInner;
}

static async Task Test()
{
    var taskOuter = DoWorkAsync();
    // Point Z: 
    await taskOuter;
    // Point B: 
    await taskOuter.Result; // await taskInner
    Console.WriteLine("request received");
}

A 点,您想知道B 点 是否有await。但此时,B点还在未来,还没有发生。你需要一台时光机:)

[UPDATE] 同样,在X 点,您无法知道Z 点await,因为代码流还没有达到Z

但是,在 Y 时,理论上您可能可以知道 Zawait(仍然不了解 B)。虽然,我不知道在技术上是否有可能获得这些信息。

【讨论】:

    【解决方案3】:

    我认为你这样做的方式很混乱。根本不清楚Task&lt;Task&gt; 应该是什么意思。我会做的是让你的方法返回类似Task&lt;Work&gt;的东西。然后Work 类型将具有类似GetResultAsync() 的方法,该方法将返回代表远程机器上执行工作的Task

    这样,您的代码含义更清晰,您还可以根据是否调用GetResultAsync(),轻松识别是否处理响应。

    【讨论】:

    • 我其实很喜欢这种方法。干净多了
    • 我最终采用了这种方法。虽然其他答案有所帮助,但这个答案给了我一个很好的方向,我很感激。
    猜你喜欢
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2015-03-17
    • 1970-01-01
    相关资源
    最近更新 更多