异步ctp递归

本文关键字:递归 ctp 异步 | 更新日期: 2023-09-27 17:59:56

我第一次玩异步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调用自己。在经典的非异步世界中,这会导致堆栈溢出。我认为异步方法不是这样的,但无论如何,我想确定一下。任何人

异步ctp递归

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

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。这使得helper成为第一,并调用DoIt。它调用Something(),取回一个任务,为该任务创建一个提示者,告诉提示者"完成后,调用helper1.DoIt"并返回。

十分之一秒后,任务完成,消息循环调用helper1的DoIt。helper1的状态为AFTERSOMETHINGSTATE,因此我们采用goto并调用Go。这就产生了helper2,并就此调用DoIt。它调用Something(),取回一个任务,为该任务创建一个提示器,告诉提示器"完成后,在helper2上调用DoIt",并将控制权返回给helper1的DoIt。这会调用SomethingElse,为该任务指定一个提示者,并告诉"当你完成其他任务时,请调用帮助者1的DoIt"。然后它返回。

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

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

不,这里没有无界递归。每次Go执行时,它都会异步启动Something(),然后返回到调用方。在"某事"发生后对事物的调用稍后发生。"Go"每次只在堆栈中出现一次。