Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步CTP和;最后";_C#_.net_C# 4.0_Async Ctp - Fatal编程技术网

C# 异步CTP和;最后";

C# 异步CTP和;最后";,c#,.net,c#-4.0,async-ctp,C#,.net,C# 4.0,Async Ctp,代码如下: static class AsyncFinally { static async Task<int> Func( int n ) { try { Console.WriteLine( " Func: Begin #{0}", n ); await TaskEx.Delay( 100 ); Console.WriteLine( " Func:

代码如下:

static class AsyncFinally
{
    static async Task<int> Func( int n )
    {
        try
        {
            Console.WriteLine( "    Func: Begin #{0}", n );
            await TaskEx.Delay( 100 );
            Console.WriteLine( "    Func: End #{0}", n );
            return 0;
        }
        finally
        {
            Console.WriteLine( "    Func: Finally #{0}", n );
        }
    }

    static async Task Consumer()
    {
        for ( int i = 1; i <= 2; i++ )
        {
            Console.WriteLine( "Consumer: before await #{0}", i );
            int u = await Func( i );
            Console.WriteLine( "Consumer: after await #{0}", i );
        }
        Console.WriteLine( "Consumer: after the loop" );
    }

    public static void AsyncTest()
    {
        Task t = TaskEx.RunEx( Consumer );
        t.Wait();
        Console.WriteLine( "After the wait" );
    }
}
如您所见,finally块的执行时间比您预期的要晚得多

有解决办法吗

提前谢谢

编辑 请考虑Theo Yaung的.

原始答案 我对async/await不太熟悉,但读完本文后:

在阅读代码时,我在
Func(int n)
函数中看到了
wait
,这意味着从
wait
关键字后面的代码开始,直到函数结束,都将作为委托执行

所以我的猜测(这是一个未经教育的猜测)是
Func:Begin
Func:End
可能会在不同的“上下文”(线程?)中执行,即异步执行

因此,
intu=wait Func(i)Func
中的代码
wait
时,
Consumer
中的代码>行将继续执行。因此,很可能有:

Consumer: before await #1
    Func: Begin #1
Consumer: after await #1
Consumer: before await #2
    Func: Begin #2
Consumer: after await #2
Consumer: after the loop
    Func: End #1         // Can appear at any moment AFTER "after await #1"
                         //    but before "After the wait"
    Func: Finally #1     // will be AFTER "End #1" but before "After the wait"
    Func: End #2         // Can appear at any moment AFTER "after await #2"
                         //    but before "After the wait"
    Func: Finally #2     // will be AFTER "End #2" but before "After the wait"
After the wait           // will appear AFTER the end of all the Tasks
Func:End
Func:Finally
可以出现在日志中的任何位置,唯一的限制是
Func:End#X
将出现在其关联的
Func:Finally#X
之前,并且这两者都应该出现在等待后的
之前

正如Henk Holterman(有点突然)所解释的,您在
Func
主体中放置了一个
wait
,这意味着后面的一切有时都会在后面执行

函数的
开始
结束
之间放置了一个
等待
,因此没有解决办法


就我那没受过教育的2欧分。

这是一个极好的捕获-我同意CTP中实际上有一个bug。我仔细研究了一下,结果如下:

这是异步编译器转换的CTP实现,以及.NET4.0+中TPL(任务并行库)的现有行为的组合。以下是起作用的因素:

  • 源代码中的finally主体被转换为实际CLR finally主体的一部分。出于许多原因,这是可取的,其中一个原因是我们可以让CLR执行它,而无需额外捕获/重试异常。这也在某种程度上简化了我们的代码生成—简单的代码生成在编译后会产生更小的二进制文件,这是我们的许多客户绝对希望的。:)
  • Func(int n)
    方法的首要任务是真正的第三方物流任务。当您在
    Consumer()
    中等待
    时,
    Consumer()
    方法的其余部分实际上是作为从
    Func(int n)
    返回的
    任务完成后的继续安装的
  • CTP编译器转换异步方法的方式导致
    return
    在实际返回之前映射到
    SetResult(…)
    调用<代码>设置结果(…)
  • 归结为对的调用
  • TaskCompletionSource.TrySetResult
    表示TPL任务完成。立即使其继续发生“某个时候”。这个“有时”可能意味着在另一个线程上,或者在某些情况下,TPL是聪明的,并且说“嗯,我现在可以在同一个线程上调用它”
  • Func(int n)
    的首要
    任务
    在最终运行之前就在技术上“完成”。这意味着在异步方法上等待的代码可以在并行线程中运行,甚至在finally块之前运行
  • 考虑到首要的
    任务
    应该表示方法的异步状态,基本上,在至少所有用户提供的代码都按照语言设计执行之前,它不应该被标记为已完成。我将与Anders、语言设计团队和编译器开发人员一起讨论这个问题


    表现范围/严重程度:

    static async Task<int> Func( int n )
    {
        int result;
        try
        {
            Func<Task<int>> helperLambda = async() => {
                Console.WriteLine( "    Func: Begin #{0}", n );
                await TaskEx.Delay( 100 );
                Console.WriteLine( "    Func: End #{0}", n );        
                return 0;
            };
            result = await helperLambda();
        }
        finally
        {
            Console.WriteLine( "    Func: Finally #{0}", n );
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> Func(int n)
    {
        int result;
        try
        {
            result = await HelperMethod(n);
        }
        finally
        {
            Console.WriteLine("    Func: Finally #{0}", n);
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> HelperMethod(int n)
    {
        Console.WriteLine("    Func: Begin #{0}", n);
        await TaskEx.Delay(100);
        Console.WriteLine("    Func: End #{0}", n);
        return 0;
    }
    
    在WPF或WinForms的情况下,如果您有某种托管消息循环,您通常不会被这一点咬到。原因是
    任务
    上的
    等待
    的实现取决于。这将导致异步延续在预先存在的消息循环上排队,并在同一线程上运行。您可以通过以下方式将代码更改为运行
    Consumer()
    来验证这一点:

        DispatcherFrame frame = new DispatcherFrame(exitWhenRequested: true);
        Action asyncAction = async () => {
            await Consumer();
            frame.Continue = false;
        };
        Dispatcher.CurrentDispatcher.BeginInvoke(asyncAction);
        Dispatcher.PushFrame(frame);
    
    在WPF消息循环的上下文中运行后,输出将按预期显示:

    Consumer: before await #1
        Func: Begin #1
        Func: End #1
        Func: Finally #1
    Consumer: after await #1
    Consumer: before await #2
        Func: Begin #2
        Func: End #2
        Func: Finally #2
    Consumer: after await #2
    Consumer: after the loop
    After the wait
    

    解决方法:

    static async Task<int> Func( int n )
    {
        int result;
        try
        {
            Func<Task<int>> helperLambda = async() => {
                Console.WriteLine( "    Func: Begin #{0}", n );
                await TaskEx.Delay( 100 );
                Console.WriteLine( "    Func: End #{0}", n );        
                return 0;
            };
            result = await helperLambda();
        }
        finally
        {
            Console.WriteLine( "    Func: Finally #{0}", n );
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> Func(int n)
    {
        int result;
        try
        {
            result = await HelperMethod(n);
        }
        finally
        {
            Console.WriteLine("    Func: Finally #{0}", n);
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> HelperMethod(int n)
    {
        Console.WriteLine("    Func: Begin #{0}", n);
        await TaskEx.Delay(100);
        Console.WriteLine("    Func: End #{0}", n);
        return 0;
    }
    
    唉,解决方法是将代码更改为在
    try/finally
    块中不使用
    return
    语句。我知道这真的意味着您在代码流中失去了很多优雅。您可以使用异步助手方法或助手lambda来解决此问题。就个人而言,我更喜欢helper lambdas,因为它会自动关闭包含方法中的局部变量/参数,并使相关代码更接近

    辅助Lambda方法:

    static async Task<int> Func( int n )
    {
        int result;
        try
        {
            Func<Task<int>> helperLambda = async() => {
                Console.WriteLine( "    Func: Begin #{0}", n );
                await TaskEx.Delay( 100 );
                Console.WriteLine( "    Func: End #{0}", n );        
                return 0;
            };
            result = await helperLambda();
        }
        finally
        {
            Console.WriteLine( "    Func: Finally #{0}", n );
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> Func(int n)
    {
        int result;
        try
        {
            result = await HelperMethod(n);
        }
        finally
        {
            Console.WriteLine("    Func: Finally #{0}", n);
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> HelperMethod(int n)
    {
        Console.WriteLine("    Func: Begin #{0}", n);
        await TaskEx.Delay(100);
        Console.WriteLine("    Func: End #{0}", n);
        return 0;
    }
    
    静态异步任务函数(int n)
    {
    int结果;
    尝试
    {
    Func helperLambda=async()=>{
    WriteLine(“Func:Begin{0}”,n);
    等待TaskEx.延迟(100);
    Console.WriteLine(“Func:End{0}”,n);
    返回0;
    };
    结果=等待帮助程序lambda();
    }
    最后
    {
    WriteLine(“Func:Finally{0}”,n);
    }
    //由于Func(…)的return语句在try/finally之外,
    //即使面对这个bug,finally主体也肯定会首先执行。
    返回结果;
    }
    
    辅助方法方法:

    static async Task<int> Func( int n )
    {
        int result;
        try
        {
            Func<Task<int>> helperLambda = async() => {
                Console.WriteLine( "    Func: Begin #{0}", n );
                await TaskEx.Delay( 100 );
                Console.WriteLine( "    Func: End #{0}", n );        
                return 0;
            };
            result = await helperLambda();
        }
        finally
        {
            Console.WriteLine( "    Func: Finally #{0}", n );
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> Func(int n)
    {
        int result;
        try
        {
            result = await HelperMethod(n);
        }
        finally
        {
            Console.WriteLine("    Func: Finally #{0}", n);
        }
        // since Func(...)'s return statement is outside the try/finally,
        // the finally body is certain to execute first, even in face of this bug.
        return result;
    }
    
    static async Task<int> HelperMethod(int n)
    {
        Console.WriteLine("    Func: Begin #{0}", n);
        await TaskEx.Delay(100);
        Console.WriteLine("    Func: End #{0}", n);
        return 0;
    }
    
    静态异步任务函数(int n)
    {
    int结果;
    尝试
    {
    结果=等待帮助方法(n);
    }
    最后
    {
    WriteLine(“Func:Finally{0}”,n);
    }
    //由于Func(…)的return语句在try/finally之外,
    //最后的身体肯定会