ConfigureAwait:异常是在哪个线程上处理的?

10
当你使用 await 关键字等待一个 Task 时,默认情况下延续操作会在同一线程上运行。唯一需要这样做的情况是当你处于 UI 线程时,同时延续操作也需要在 UI 线程上运行。
你可以通过使用 ConfigureAwait 来控制这个过程,例如:
await SomeMethodAsync().ConfigureAwait(false);

...这可以用来卸载UI线程上不需要运行的工作。 (但请参见下面Stephen Cleary的评论。)

现在考虑一下这段代码:

try
{
    await ThrowingMethodAsync().ConfigureAwait(false);
}
catch (Exception e)
{
    // Which thread am I on now?
}

这个怎么样?
try
{
    await NonThrowingMethodAsync().ConfigureAwait(false);

    // At this point we *may* be on a different thread

    await ThrowingMethodAsync().ConfigureAwait(false);
}
catch (Exception e)
{
    // Which thread am I on now?
}

2
async/await 的第一个版本确实支持异常处理,但新的改进在于你现在可以在 catch 块中调用 await,而之前是不允许的。在 C# 5 中,在 try 块中调用 await 是完全没有问题的。 - Scott Chamberlain
@Scott:感谢您的纠正! - Petter Hesselberg
已相应地更新了问题。 - Petter Hesselberg
2
@PetterHesselberg:“当您等待任务时,默认情况下,继续运行在同一线程上。”不,这是不正确的。我有一个async介绍,解释了异步方法如何恢复。此外,“这对于卸载不需要在UI线程上运行的工作非常有用”是可疑的-只有在异步操作实际上异步完成时才是真的;如果它同步完成(例如,下载缓存的资源),它将不会离开UI线程。卸载工作的正确方法是Task.Run - Stephen Cleary
@Stephen:感谢您的澄清! - Petter Hesselberg
1个回答

10
异常会出现在任何线程上,如果没有异常,继续运行的线程将会执行。
try
{
    await ThrowingMethodAsync().ConfigureAwait(false);
}
catch (Exception e)
{
    // Which thread am I on now?
    //A: Likely a Thread pool thread unless ThrowingMethodAsync threw 
    //   synchronously (without a await happening first) then it would be on the same
    //   thread that the function was called on.
}

try
{
    await NonThrowingMethodAsync().ConfigureAwait(false);

    // At this point we *may* be on a different thread

    await ThrowingMethodAsync().ConfigureAwait(false);
}
catch (Exception e)
{
    // Which thread am I on now?
    //A: Likely a Thread pool thread unless ThrowingMethodAsync threw 
    //   synchronously (without a await happening first) then it would be on the same
    //   thread that the function was called on.
}

一些更明确的解释:

对于一些更加清晰的解释:

private async Task ThrowingMethodAsync()
{
    throw new Exception(); //This would cause the exception to be thrown and observed on 
                           // the calling thread even if ConfigureAwait(false) was used.
                           // on the calling method.
}

private async Task ThrowingMethodAsync2()
{
    await Task.Delay(1000);
    throw new Exception(); //This would cause the exception to be thrown on the SynchronizationContext
                           // thread (UI) but observed on the thread determined by ConfigureAwait
                           // being true or false in the calling method.
}

private async Task ThrowingMethodAsync3()
{
    await Task.Delay(1000).ConfigureAwait(false);
    throw new Exception(); //This would cause the exception to be thrown on the threadpool
                           // thread but observed on the thread determined by ConfigureAwait
                           // being true or false in the calling method.
}

请问你的回答是什么意思? 对我来说有点困惑,异常会被处理还是不会被处理? 异常将在计划的任何线程上发生。 这对我来说意味着,在ThreadPoolThread或OriginThread上计划继续执行, 但是,如果没有异常,你所说的“on had there been no exception”是什么意思? 你是指它会像从未发生过异常一样寻找try-catch吗? - Franz
听起来像是对我来说,既是肯定也是否定的答案。 - Franz

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