2012-05-30 44 views
21

在C#中使用異步CTP或vs.net 2011測試版,我們可以編寫遞歸代碼:在C#中異步遞歸是安全的嗎(async ctp/.net 4.5)?

public async void AwaitSocket() 
{ 
    var socket = await this.AcceptSocketAsync(); //await socket and >>return<< to caller 
    AwaitSocket(); //recurse, note that the stack will never be deeper than 1 step since await returns.. 
    Handle(socket); // this will get called since "await" returns 
} 

在這個特定的示例,代碼異步等待TCP套接字一旦被接受,它將緩存和異步等待另一個。

這似乎工作正常,因爲await部分將使代碼返回到調用方,因此,不會導致堆棧溢出。

所以兩個問題在這裏:

  1. 如果我們忽略我們正在處理此示例中插座的事實。 以這種方式進行堆棧自由遞歸是否可行?或者我缺少什麼缺點?

  2. 從IO的角度來看,上面的代碼是否足以處理所有傳入的請求? 我的意思是等待一個,一旦被接受,就開始等待另一個。 某些請求會因某種原因而失敗嗎?

+1

那麼,什麼時候'處理(套接字)'運行? – leppie

+2

我沒有看到它本身有什麼問題,但是它爲IMO更直接的'公共異步void AwaitSocket(){while(true){var socket = await this.AcceptSocketAsync();處理(插座); }}'? – hvd

+0

@leppie在'AwaitSocket();'返回後。是的,它確實會回來。 – hvd

回答

2

從上面的討論,我猜這樣的事情是最好的辦法。 請給予反饋

public async void StartAcceptingSockets() 
{ 
    await Task.Yield(); 
    // return to caller so caller can start up other processes/agents 
    // TaskEx.Yield in async ctp , Task.Yield in .net 4.5 beta 

    while(true) 
    { 
     var socket = await this.AcceptSocketAsync(); 
     HandleAsync(socket); 
     //make handle call await Task.Yield to ensure the next socket is accepted as fast 
     //as possible and dont wait for the first socket to be completely handled 
    } 
} 

private async void HandleAsync(Socket socket) 
{ 
     await Task.Yield(); // return to caller 

     ... consume the socket here... 
} 
+0

如果AcceptSocketAsync()或HandleAsync()拋出異常,會發生什麼? – svick

+0

是的,如果HandleAsync在await yield部分之後拋出,會發生什麼情況?如果繼續在線程池中處理並且代碼拋出,這將終止線程池線程,對吧? –

+1

如果異常從'async void'拋出,則直接傳遞給「上下文」。如果繼續在線程池上下文中運行,這將導致在線程池線程上直接引發異常,導致進程崩潰。通常,除非它們是事件處理程序(因此*必須*爲'void'),否則您應該讓所有'async'方法返回'Task' /'Task '。可以這樣想:'async void'是*允許*,不是*推薦*。 –