递归和的await /异步关键词 [英] Recursion and the await / async Keywords

查看:295
本文介绍了递归和的await /异步关键词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何使用等待关键字作品脆弱的把握,我想延长我对它的理解有点。

I have a fragile grasp of how the await keyword works, and I want to extend my understanding of it a bit.

这还是让我目瞪口呆的问题是使用递归过程。这里有一个例子:

The issue that still makes my head spin is the use of recursion. Here's an example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestingAwaitOverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = TestAsync(0);
            System.Threading.Thread.Sleep(100000);
        }

        static async Task TestAsync(int count)
        {
            Console.WriteLine(count);
            await TestAsync(count + 1);
        }
    }
}

这其中显然抛出一个 StackOverflowException

我的理解是,因为code实际上同步运行,直到第一个异步操作,之后返回一个包含关于异步操作的信息工作对象。在这种情况下,不存在异步操作,因此,它只是不断的虚假承诺下进行递归,它最终会得到一个工作返回。

My understanding is because the code actually runs synchronously until the first asynchronous action, after which it returns a Task object that contains information about the asynchronous operation. In this case, there is no asynchronous operation, thus it just keeps recursing under the false promise that it will eventually get a Task returned.

现在改变它只是一点点:

Now changing it just a tiny bit:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestingAwaitOverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = TestAsync(0);
            System.Threading.Thread.Sleep(100000);
        }

        static async Task TestAsync(int count)
        {
            await Task.Run(() => Console.WriteLine(count));
            await TestAsync(count + 1);
        }
    }
}

这一个不抛出 StackOverflowException 。我的 sortof 的明白为什么它的工作原理,但我把它更多的是直觉的感觉(它可能与code是如何安排使用回调以避免建设栈的交易,但我可以T把这一预感到的解释)

This one does not throw a StackOverflowException. I can sortof see why it works, but I would call it more of a gut feeling (it probably deals with how the code is arranged to use callbacks to avoid building the stack, but I can't translate that gut feeling into an explanation)

所以,我有两个问题:


  • 如何在第二批code的避免 StackOverflowException

  • 是否第二批code浪费其他资源? (例如,它在堆上分配一个荒谬的大量任务的对象?)

谢谢!

推荐答案

部分最多的功能第一的await同步运行。在第一种情况下,它运行到因为这个堆栈溢出 - 没有什么中断函数调用本身

The part up to the first await in any function runs synchronously. In the first case it runs into a stack overflow because of that - there is nothing interrupting the function calling itself.

第一的await(不立即完成 - 这是一种具有高的情形产生对你的情况)导致函数返回(并放弃它的堆栈空间!)。它会将它的其余部分作为一个延续。该TPL确保延续从未窝太深。如果有堆栈溢出的危险继续排队到线程池,重新堆栈(这是开始填写)。

The first await (which does not complete immediately - this is the case for you with high likelyhood) causes the function to return (and to give up its stack space!). It queues the rest of it as a continuation. The TPL ensures that continuations never nest too deeply. If there is a risk of stack overflow the continuation is queued to the thread pool, resetting the stack (which was starting to fill up).

第二个例子仍然可以溢出!如果在 Task.Run 任务总是立即完成? (这是不可能的,但有合适的操作系统线程调度可能)。然后,异步函数永远不会被中断(使其返回,并释放所有堆栈空间),并会导致相同的行为的情况下,1

The second example can still overflow! What if the Task.Run task always completed immediately? (This is unlikely but possible with the right OS thread scheduling). Then, the async function would never be interrupted (causing it to return and free all stack space) and the same behavior as in case 1 would result.

这篇关于递归和的await /异步关键词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆