c# - 异步ctp递归

标签 c# recursion async-ctp

我第一次使用 async CTP 进行了大约 15 分钟...(很好)。

这是我组装的一个非常简单的服务器:

internal class Server
{
    private HttpListener listener;
    public Server()
    {
        listener = new HttpListener();
        listener.Prefixes.Add("http://*:80/asynctest/");
        listener.Start();
        Go();
    }

    async void Go()
    {
        HttpListenerContext context = await listener.GetContextAsync();
        Go();
        using (var httpListenerResponse = context.Response) 
        using (var outputStream = httpListenerResponse.OutputStream) 
        using (var sw = new StreamWriter(outputStream))
        {
            await sw.WriteAsync("hello world");
        }
    }
}

可以看出,异步方法 Go 调用了自身。在经典的非异步世界中,这会导致堆栈溢出。我假设异步方法不是这种情况,但我想以某种方式确定。有人吗?

最佳答案

让我们把它分解成更简单的东西:

async static void Go()
{
    await Something();
    Go();
    await SomethingElse();
}

编译器如何处理这个?

基本上这变成了这个草图:

class HelperClass
{
    private State state = STARTSTATE;
    public void DoIt()
    {

        if (state == STARTSTATE) goto START;
        if (state == AFTERSOMETHINGSTATE) goto AFTERSOMETHING;
        if (state == AFTERSOMETHINGELSESTATE) goto AFTERSOMETHINGELSE;

        START:
        {
           state = AFTERSOMETHINGSTATE;
           var awaiter = Something().MakeAnAwaiter();
           awaiter.WhenDoneDo(DoIt);
           return;
        }

        AFTERSOMETHING:
        {
           Go();
           state = AFTERSOMETHINGELSESTATE;
           var awaiter = SomethingElse().MakeAnAwaiter();
           awaiter.WhenDoneDo(DoIt);
           return;
        }

        AFTERSOMETHINGELSE:

        return;
    }

    static void Go()
    {
        var helper = new HelperClass();
        helper.DoIt();
    }

现在您只需要记住,当每个异步操作完成时,“DoIt”将被消息循环再次调用(当然是在助手的适当实例上)。

那么会发生什么?解决它。您第一次调用 Go。这使助手成为第一位并调用 DoIt。这会调用 Something(),返回一个任务,为该任务创建一个等待者,告诉等待者“完成后,调用 helper1.DoIt”并返回。

十分之一秒后任务完成,消息循环调用 helper1 的 DoIt。 helper1 的状态是 AFTERSOMETHINGSTATE,因此我们使用 goto 并调用 Go。这使得 helper2 并在其上调用 DoIt。这会调用 Something(),返回一个任务,为该任务创建一个等待者,告诉等待者“当你完成后,在 helper2 上调用 DoIt”并将控制权返回给 helper1 的 DoIt。这会调用 SomethingElse,为该任务创建一个等待者,并告诉它“当你完成其他事情时,调用 helper1 的 DoIt”。然后返回。

现在我们有两个未完成的任务,堆栈上没有代码。其中一项任务将首先完成。假设 SomethingElse 任务首先完成。消息循环调用 helper1.DoIt(),它会立即返回。 Helper1 现在是垃圾。

稍后消息循环调用 helper2.DoIt(),并分支到 AFTERSOMETHING。现在调用 Go(),创建 helper3...

所以不,这里没有无限递归。每次 Go 执行时,它都会异步启动 Something(),然后返回给调用者。在“某事”之后对这些东西的调用稍后发生。 “Go”一次只会在堆栈中出现一次。

关于c# - 异步ctp递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6447626/

相关文章:

java - 如何向后实现递归算法

c# - "async"关键字附近显示错误,但构建成功

c# - 提高网站数据库的搜索性能

c# - C#套接字BeginAccept事件停止触发

java - 在 .jj 文件中检测到左递归

windows-phone-7 - 在 Visual Studio 2012 中针对 WP7 异步驱动的项目

c# - 为隐式调度方法显式指定 TaskScheduler

c# - C#/Java 中动态对象的限制

c# 如何建立UDP套接字连接

php - 如何递归构建树深度未知的 <select>