2014-02-10 71 views
1

我有一個方法HandleAcceptedConnection是Task.Run(),我想異步運行(在另一個單獨的線程)。我試圖聲明HandleAcceptedConnection作爲異步方法,不要調用await,但它似乎不是異步運行。我可以確認我可以在另一個Task.Run()下面使用Task.Run()(通過觀察線程ID),但推薦使用它嗎?我可以將Task.Run包裝在另一個Task.Run()下嗎?

private async void Start_Click(object sender, RoutedEventArgs e) 
{ 
     var task = Task.Run(() => 
     { 
      while (isContinue) 
      { 
       var handler = listener.Accept(); 
       // handle connection 

       Log("Before"); 
       Log("ThreadId Accept " + Thread.CurrentThread.ManagedThreadId); 

       // i want to run method below asynchronously. i want to 
       // wrap it under Task.Run() but i am already under 
       // Task.Run(). i set HandleAcceptedConnection as async. i thought by not 
       // calling await on HandleAcceptedConnection, HandleAcceptedConnection 
       // is asynchronous 
       HandleAcceptedConnection(handler); 

       Log("After"); 

       isContinue = true; 
      } 
     }); 
     await task; 
} 

private async Task HandleAcceptedConnection(Socket handler) 
{ 
    Log("ThreadId HandleAcceptedConnection " + Thread.CurrentThread.ManagedThreadId); 
    Log("Under HandleAcceptedConnection"); 
    Thread.Sleep(10000); 
} 

當我運行此,日誌說

Before 
Under HandleAcceptedConnection 
After 

我想

Before 
After 
Under HandleAcceptedConnection 

我想HandleAcceptedConnection被異步運行。我應該將它包裝在另一個Task.Run中,還是它已經是異步的?

+4

你的方法同步運行,因爲它不包含'await'聲明。但即使它*異步運行,這也就意味着您根本無法保證「After」和「Under」出現的順序。如果您需要*「After」出現在「Under」之前, ,只需將方法調用移動到最後。你想在這裏做什麼? – Jon

+3

我認爲你需要更深入地讀入async/await/Tasks。主要理解:async/await/Task不一定等於多線程。 – Krumelur

+0

@Jon「」之下「之後」之前的「」之後的「」僅僅是指示HandleAcceptedConnection是同步還是異步運行。知道HandleAcceptedConnection是否運行異步的更好方法是通過監視線程(我剛剛添加)。我想要的只是在'上面的調用者'的另一個線程/異步中運行HandleAcceptedConnection。 –

回答

1

你應該使用AcceptTcpClientAsync,那麼你將不需要額外的線程。以this answer爲例。當有可用的自然異步版本時,不要使用同步API。

更新爲解決評論。沒有什麼能阻止你使用Task.Run從內Task.Run,你的代碼可能是這樣的(未經測試):

private async void Start_Click(object sender, RoutedEventArgs e) 
{ 
    var connectionTasks = new List<Task>(); 

    Func<Task> handleConnection = async() => 
    { 
     var connectionTask = Task.Run(() => HandleAcceptedConnection(handler)); 
     connectionTasks.Add(connectionTask); 
     await connectionTask; 
     connectionTasks.Remove(connectionTask); 
    }; 

    var task = Task.Run(() => 
    { 
     while (isContinue) 
     { 
      var handler = listener.Accept(); 
      // handle connection 

      Log("Before"); 
      Log("ThreadId Accept " + Thread.CurrentThread.ManagedThreadId); 

      var connectionTask = handleConnection(); 

      Log("After"); 

      isContinue = true; 
     } 
    }); 
    await task; 
} 
+0

我使用的網絡庫中沒有AcceptTcpClientAsync。實際上,所有暴露的方法在我使用的網絡庫中都是同步的。 –

+1

@publicENEMY,我明白了。你應該在你的問題中澄清這一點。我現在回想起來,還有另一個問題,你提到了一個支持異步的第三方套接字庫,但明天我不會記得:) – Noseratio

+0

LOL。抱歉。我不想提到有關套接字或網絡的任何內容,因爲問題實際上是關於異步的東西。 –

2

你嘗試

private async Task HandleAcceptedConnection(Socket handler) 
{ 
    Thread.Sleep(1000); 
    Log("Under HandleAcceptedConnection"); 
} 

因爲在另一個線程做的東西並不意味着它會被延遲。

+2

更好地使用'Task.Delay()' - 它不會通過阻塞來浪費線程。然後你將不得不等待它 - 否則,首先使方法「async」沒有什麼意義。 – Krumelur

+1

@Krumelur不僅*更好*。他/她必須使用'await Task.Delay(1000);'來獲得所需的效果。 –

+1

@ L.B我不明白他想解決什麼問題,所以我不確定期望的效果是什麼:-) – Krumelur