2016-03-07 77 views
1

MS had said that both APM and EAP are outdated開始,在.NET Framework中推薦使用TAP進行異步編程。然後我想轉換從APM我的代碼爲TAP:將APM迭代調用轉換爲TAP

public class RpcHelper 
{ 
    public void DoReadViaApm(IRpc rpc, BlockingCollection<ArraySegment<byte>> bc) 
    { 
     byte[] buf = new byte[4096]; 
     rpc.BeginRead(buf, 0, buf.Length, 
      ar => 
      { 
       IRpc state = (IRpc) ar.AsyncState; 
       try 
       { 
        int nb = state.EndRead(ar); 
        if (nb > 0) 
        { 
         bc.Add(new ArraySegment<byte>(buf, 0, nb)); 
        } 
       } 
       catch (Exception ignored) 
       { 
       } 
       finally 
       { 
        DoReadViaApm(state, bc); 
       } 
      }, 
      rpc); 
    } 

    public void DoReadViaTap(IRpc rpc, BlockingCollection<ArraySegment<byte>> bc) 
    { 
     Task.Factory.StartNew(() => 
     { 
      while (true) 
      { 
       Task<byte[]> task = rpc.ReadAsync(); 
       try 
       { 
        task.Wait(-1); 
        if (task.Result != null && task.Result.Length > 0) 
        { 
         bc.Add(new ArraySegment<byte>(task.Result)); 
        } 
       } 
       catch (Exception ignored) 
       { 
       } 
      } 
     }, TaskCreationOptions.LongRunning); 
    } 
} 

public interface IRpc 
{ 
    IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state); 
    int EndRead(IAsyncResult asyncResult); 

    Task<byte[]> ReadAsync(); 
} 

的TAP方法DoReadViaTap()使用TaskCreationOptions.LongRunning,它看起來非常難看。我可以讓DoReadViaTap()看起來更像DoReadViaApm()嗎?

回答

0

我不完全確定你的代碼應該做什麼,但我想這是一些工人等待輸入? 您可以通過使用await來簡化它,並使啓動的操作異步。請注意任務有超時,所以您可能需要適當設置或捕獲異常。

public void DoReadViaTap(IRpc rpc, BlockingCollection<ArraySegment<byte>> bc) 
{ 
    Task.Factory.StartNew(async() => 
    { 
     while (true) 
     { 
      byte[] result = await rpc.ReadAsync(); 
      if (result.Length > 0) 
      { 
       bc.Add(new ArraySegment<byte>(result)); 
      } 
      catch (AggregateException ignored) 
      { 
      } 
     } 
    }, TaskCreationOptions.LongRunning); 
} 
+0

你的代碼看起來更好,但不是我所期望的。我想殺死長時間運行的任務,因爲DoReadViaApm()很快就會使用IO線程。 –

+0

你的意思是由'Task.Factory.StartNew()'創建的任務?您可以使用取消標記來檢查該任務是否應該取消。 [示例](http://stackoverflow.com/a/19932396/2300387) –

+0

'try'去了哪裏?沒有它,catch就不會編譯。 – svick

0

你應該做的是使用async - await。當你這樣做,你不需要啓動Task

public async Task DoReadViaTap(IRpc rpc, BlockingCollection<ArraySegment<byte>> bc) 
{ 
    while (true) 
    { 
     try 
     { 
      byte[] result = await rpc.ReadAsync().ConfigureAwait(false); 
      if (result != null && result.Length > 0) // or result?.Length > 0 on C# 6 
      { 
       bc.Add(new ArraySegment<byte>(result)); 
      } 
     } 
     catch (Exception ignored) 
     { 
     } 
    } 
} 

對我來說,這比讀的APM版本要好很多。

請注意,我不認爲完全忽略異常和無限循環,沒有辦法結束它們是好的做法,我只是複製了代碼中的那些。

+0

我正在尋找無限的鏈式任務構造: start: Task task = rpc.ReadAsync(); task.ContinueWith { bc.Add(new ArraySegment (result)); 轉到開始: } –

+0

@CauchySong爲什麼?這會比使用'async'-'await'更加混亂,就像你的APM代碼一樣。 – svick