10

我有一个方法

public Task<Task> DoSomeWorkOnARemoteMachine()

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

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

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

要调用此方法,我使用:

await await DoSomeWorkOnARemoteMachine();

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

await DoSomeWorkOnARemoteMachine();

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

因此,我的问题是:a 是否有可能Task“知道”它是否正在被await编辑并且如果不是则不执行,或者执行一些其他代码路径(例如空Task主体)。

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

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

4

3 回答 3

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点还在未来,还没有发生。你需要一台时光机:)

[更新]同样,在Point X处,您无法知道Point Zawait处的,因为代码流尚未到达Z

但是,当在Y时,理论上您可能知道awaitat Z(仍然不是关于B)。虽然,我不知道在技术上是否有可能获得这些信息。

于 2013-11-06T08:23:41.887 回答
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...
于 2013-11-06T08:28:53.843 回答
2

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

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

于 2013-11-06T15:07:05.393 回答