简体   繁体   English

C#“等待”实际上返回什么?

[英]What does C# “await” actually return?

Below is some code that runs "as is" in LinqPad. 下面是一些在LinqPad中“按原样”运行的代码。 It demonstrates my misunderstanding of what await is doing. 它表明了我对正在await的事情的误解。 See further down for results and my issue. 进一步了解结果和我的问题。

    void Main()
{
    var cts = new CancellationTokenSource();
    StartIt(cts.Token);
    Thread.Sleep(500);
    "Cancelling".Dump();
    cts.Cancel();
}


// Define other methods and classes here
async Task StartIt(CancellationToken token)
{
    "StartIt".Dump();
    var o = new TestClass();

    await o.Step0(token);

}

public class TestClass
{
    public async Task Step0(CancellationToken token)
    {
        var t = Step1(token);
        ("Step0.Task.Id => " + t.Id).Dump();        

        await t;
        ("Step0.IsCancelled? " + t.IsCanceled).Dump();
    }

    public async Task Step1(CancellationToken token)
    {
        var t = Step2(token);
        ("Step1.Task.Id => " + t.Id).Dump();

        try {
            await t;
        }
        catch (OperationCanceledException)
        {
            "Step1.OperationCanceledException".Dump();
        }
        ("Step1.IsCancelled? " + t.IsCanceled).Dump();
    }

    public Task Step2(CancellationToken token)
    {
        return Task.Run(() =>{
                Thread.Sleep(3000);
                token.ThrowIfCancellationRequested();
                "Done".Dump();
            }, token);
    }
}

So the above produces: 因此上面产生:

StartIt
Step1.Task.Id => 17
Step0.Task.Id => 18
Cancelling
Step1.OperationCanceledException
Step1.IsCancelled? True
Step0.IsCancelled? False

My issues: 我的问题:

I expect Step0's and Step1's task.Id to be the same. 我希望Step0和Step1的task.Id相同。 (therefore) I expect the cancellation that occurs to propagate up the methods so that I can interrogate t.IsCanceled and take appropriate action. (因此)我希望取消会传播到方法上,以便我可以询问t.IsCanceled并采取适当的措施。

But I'm getting a different Task being returned to Step0 . 但是我得到了一个不同的Task返回到Step0 What am I missing? 我想念什么?

Thanks 谢谢

I recommend that you read my introduction to async . 我建议您阅读async Also, there's an excellent tutorial built-in to LinqPad (Samples -> Download/import more samples -> Asynchrony in C# 5 Interactive Tutorial). 另外,LinqPad内置了一个出色的教程(《 C#5交互式教程》中的[示例->下载/导入更多示例->异步)。

Task identifiers in async code can be a bit tricky. async代码中的任务标识符可能有些棘手。 What happens is that every async Task method creates its own task that represents that method invocation. 发生的情况是,每个async Task方法都会创建自己的任务,以表示该方法的调用。 So, Task.Run creates a Task and returns it to Step2 and Step1 (id 17 in your test). 因此, Task.Run创建一个Task并将其返回到Step2Step1 (测试中的ID 17 )。 Step1 also creates a Task and returns it to Step0 (id 18 in your test). Step1还会创建一个Task ,并将其返回到Step0 (测试中的ID 18 )。 Step0 also creates a Task and returns it to StartIt , and StartIt also creates a Task and returns it to Main . Step0还创建一个Task并将其返回给StartIt ,而StartIt也创建一个Task并将其返回给Main

So, the Task returned by Task.Run (which is the same Task returned by Step2 ) is cancelled. 所以, Task返回的Task.Run (这是相同的Task由返回Step2 )被取消。 Step1 catches the cancelled exception, so it returns normally, and the Task returned by Step1 is not cancelled. Step1捕获已取消的异常,因此它会正常返回,并且不会取消Step1返回的Task

If you want to propagate exceptions, don't catch the cancelled exception (or if you do want to catch it to log, then re-throw it via throw; ). 如果要传播异常,请不要捕获已取消的异常(或者,如果您确实想捕获已记录的异常,请通过throw;将其重新throw; )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM