【问题标题】:Convert APM Iterative calls to TAP将 APM 迭代调用转换为 TAP
【发布时间】:2016-06-21 04:41:07
【问题描述】:

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() 吗?

【问题讨论】:

    标签: c# asynchronous task-parallel-library


    【解决方案1】:

    你应该做的是使用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 版本好得多。

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

    【讨论】:

    • 我正在寻找一个无限链式任务构造: start: Task task = rpc.ReadAsync(); task.ContinueWith { bc.Add(new ArraySegment(result));转到开始:}
    • @CauchySong 为什么?这将比使用async-await 更混乱,就像你的 APM 代码一样。
    【解决方案2】:

    我不完全确定您的代码应该做什么,但我猜是某个工作人员在等待输入? 您可以使用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);
    }
    

    【讨论】:

    • 你的代码看起来更好,但不是我所期望的。我想杀死长时间运行的任务,因为 DoReadViaApm() 只在短时间内使用 IO 线程。
    • 你是说Task.Factory.StartNew()创建的任务?您可以使用取消令牌来检查该任务是否应该被取消。 Example
    • try 去哪儿了? catch 没有它就无法编译。
    猜你喜欢
    • 1970-01-01
    • 2016-01-26
    • 2011-09-02
    • 2017-03-05
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多