有没有办法知道是否正在等待任务?

时间:2013-11-06 07:51:45

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

我有一个方法

public Task<Task> DoSomeWorkOnARemoteMachine()

,非常具有描述性,通过以下方式在远程计算机上执行某些工作:

  1. 在消息总线上排队消息,表明应该完成工作
  2. 远程代理接收消息并执行工作
  3. 工作完成,代理在消息总线上对消息进行排队,表明工作已完成
  4. 调用工作的应用程序会收到工作完成的消息
  5. 我使用Task<Task>的原因是因为第一个Task<>用于排队消息;当在远程机器上完成工作时(即,当收到来自代理的消息时),内部Task完成。远程代理在执行工作期间捕获的任何异常都将与完成消息一起传递,并在内部Task完成时重新抛出。

    要调用此方法,我使用:

    await await DoSomeWorkOnARemoteMachine();
    

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

    await DoSomeWorkOnARemoteMachine();
    

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

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

    我确实意识到我可以实现其他替代方案,例如传递“fire and forget”标志,或者为“fire and forget”添加重载。如果我能在没有客户端API更改的情况下实现这一点,那就太棒了

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

3 个答案:

答案 0 :(得分:3)

这是一个非常有趣的问题。然而,如果我理解正确的话,我相信这是不可能的,就像你提出的那样,因为它没有意义(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点仍在未来,尚未发生。你需要一台时间机器:)

[更新] 以同样的方式,在点X ,你无法知道点Z await ,因为代码流尚未达到 Z

然而,当处于 Y 时,从理论上讲,您可能可以知道 Z 处的await(仍然不是<强>乙)。虽然,我不知道技术上是否有可能掌握这些信息。

答案 1 :(得分:3)

我认为它不容易或无法有效实现(使用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...

答案 2 :(得分:2)

我认为你这样做的方式令人困惑。根本不清楚Task<Task>应该是什么意思。我要做的是让你的方法返回类似Task<Work>的东西。然后,Work类型将具有GetResultAsync()之类的方法,该方法将返回表示远程计算机上工作执行的Task

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