2011-06-22 30 views
5

Tôi khoảng 15 phút vào vở kịch đầu tiên của tôi với async CTP ... (tốt).async ctp recursion

Dưới đây là một máy chủ thực sự đơn giản tôi đã gõ với nhau:

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"); 
     } 
    } 
} 

Như có thể thấy, phương pháp async Go gọi chính nó. Trong thế giới không đồng bộ cổ điển, điều này sẽ gây ra tràn ngăn xếp. Tôi cho rằng đây không phải là trường hợp với một phương pháp async, nhưng tôi muốn chắc chắn, cách này hay cách khác. Bất kỳ ai?

Trả lời

13

Hãy phá vỡ nó xuống thành một cái gì đó đơn giản hơn:

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

giải quyết thế nào biên dịch với điều này?

Về cơ bản điều này trở thành một cái gì đó giống như bản phác họa sau:

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(); 
    } 

Bây giờ tất cả các bạn cần phải nhớ là khi mỗi hoạt động không đồng bộ hoàn tất, "DoIt" dự kiến ​​sẽ được gọi là một lần nữa bởi vòng lặp thông điệp (trên phù hợp Ví dụ về người trợ giúp tất nhiên).

Vậy điều gì sẽ xảy ra? Giải quyết. Bạn gọi Go lần đầu tiên. Điều đó làm cho số một trợ giúp và gọi DoIt. Điều đó gọi một cái gì đó(), nhận được một nhiệm vụ trở lại, làm cho một awaiter cho nhiệm vụ đó, nói với awaiter "khi bạn đang thực hiện, gọi helper1.DoIt" và trả về.

Một phần mười giây sau nhiệm vụ hoàn thành và vòng lặp tin nhắn gọi là Doper của helper1. Trạng thái của helper1 là AFTERSOMETHINGSTATE, vì vậy chúng ta lấy goto và gọi Go. Điều đó làm cho helper2 và gọi DoIt về điều đó. Điều đó gọi một cái gì đó(), nhận được một nhiệm vụ trở lại, làm cho một awaiter cho nhiệm vụ đó, nói với awaiter "khi bạn đang thực hiện, gọi DoIt trên helper2" và trả về kiểm soát trở lại của Doper helper1. Điều đó gọi SomethingElse, làm cho một awaiter cho nhiệm vụ đó, và nói với nó "khi bạn đang làm một cái gì đó khác, gọi helper1 của DoIt". Sau đó nó trở lại.

Bây giờ chúng tôi có hai nhiệm vụ nổi bật và không có mã trên ngăn xếp. Một trong những nhiệm vụ sẽ hoàn thành trước. Giả sử tác vụ SomethingElse hoàn thành trước tiên. Vòng lặp tin nhắn gọi helper1.DoIt(), trả về ngay lập tức. Helper1 giờ là rác.

Sau đó vòng lặp tin nhắn gọi helper2.DoIt() và các nhánh tới AFTERSOMETHING. Now Go() được gọi, tạo helper3 ...

Vì vậy, không, không có đệ quy vô biên nào ở đây. Mỗi lần Go thực hiện nó chạy như xa như không đồng bộ bắt đầu một cái gì đó() và sau đó nó trở về người gọi của nó. Cuộc gọi đến nội dung sau "điều gì đó" xảy ra sau đó. "Go" chỉ xuất hiện trên stack một lần.

+0

Tốt. Tôi nghi ngờ nhiều, nhưng tốt của nó để xem các cơ chế của cấu trúc cụ thể. Cảm ơn câu trả lời toàn diện như vậy (như thường lệ!). – spender

+0

@spender: Bạn được chào đón! Hãy tận hưởng CTP và vui lòng nếu bạn có câu hỏi, nhận xét, mối quan tâm, khen ngợi, phê bình mang tính xây dựng, v.v., đăng chúng lên Diễn đàn CTP Async. Chúng tôi có những người quản lý chương trình đọc hàng ngày đó và thu thập phản hồi của người dùng về tính năng rất hữu ích cho chúng tôi. –

Các vấn đề liên quan