将APM迭代调用转换为TAP

时间:2016-03-07 15:02:36

标签: c# asynchronous task-parallel-library

MS had said that both APM and EAP are outdated开始,TAP是.NET Framework中异步编程的推荐方法。然后我想将我的代码从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()吗?

2 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分: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版本要好得多。

请注意,我不认为完全忽略异常和无限循环而无法结束它们是良好做法,我只是从您的代码中复制了这些。