如何确定任务是否被“观察”?(涉及IT技术)

3
这是对这个问题的跟进。我也阅读了Stephen Toub的“Tasks and Unhandled Exceptions”,我认为我理解了任务和异常的工作原理以及“observed task”的含义。然而,我无法弄清楚如何判断一个Task是否已被观察到。是否有可能在不使用反射的情况下实现?

我想借鉴@Noseratio的代码作为示例:

static async void Observe(Task task)
{        
    await task; 
}

// ...

var taskObserved = false;
var task = DoSomething()
try
{
    bool ready = await DoSomethingElse();
    if (!ready) 
      return null;

    var value = await DoThirdThing(); // depends on DoSomethingElse
    taskObserved = true;
    return value + await task;
 }
 finally
 {
     if (!taskObserved)
        Observe(task);
 }

如果我们可以知道任务是否被观察到,那么这个过程就可以变得更简单和易于阅读:
static async void Observe(Task task)
{        
    if (!task.WasObserved) 
        await task; 
}

// ...

var task = DoSomething()
try
{
    bool ready = await DoSomethingElse();
    if (!ready) 
      return null;

    var value = await DoThirdThing(); // depends on DoSomethingElse
    return value + await task;
}
finally
{
    Observe(task);
}
1个回答

5

任务不知道它们是否已经被等待。这有点像询问整数是否知道它是否已经被加到另一个整数中。

然而,任务的异常可以被观察到,并且任务是否已经观察到异常实际上是被记住的。需要区分未观测的异常未等待的任务之间的区别。运行时对于未观测任务异常有一些特殊逻辑,但不会对未等待的任务进行任何特殊处理。

您真的不应编写依赖于任务是否已被等待的代码。如果DoSomething的语义是即使结果被忽略也始终应该被等待(这是一个非常奇怪但技术上有效的要求),那么以下代码就足够了:

var task = DoSomething();
try
{
  bool ready = await DoSomethingElse();
  if (!ready) 
    return null;

  var value = await DoThirdThing(); // depends on DoSomethingElse
  return value + await task;
}
finally
{
  await task;
}

另一方面,如果 DoSomething 的语义是:如果结果不需要,那么可以忽略该任务(这种情况更为常见),则以下代码应该足够:

var task = DoSomething();
bool ready = await DoSomethingElse();
if (!ready) 
  return null;

var value = await DoThirdThing(); // depends on DoSomethingElse
return value + await task;

不需要纠结于任务是否已被等待的问题。

谢谢Stephen,我希望你能发表一个答案。实际上,我对“观察”状态感兴趣(而不是“等待”状态)。例如,如果Task.Exception已被触发等。但是,我对您的第一个代码片段有一个问题,它不会抛出相同的异常两次吗?所以我会失去第一次抛出的堆栈帧吗? - avo
1
如果task以故障状态完成,则不会丢失堆栈帧。堆栈已经被捕获并放置在task.Exception中的Exception对象上。await足够聪明,可以两次保留捕获的堆栈。 - Stephen Cleary
理想情况下,如果DoSomethingElseDoThirdThing抛出异常,我仍然希望能够传播这些异常,以便与DoSomething一起抛出。但是,在这种情况下,DoSomething接管了这些异常。 - avo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接