2016-03-07 97 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