C# 如何在 WCF 回调上使用具有 APM-TAP 模式的完成端口执行 Asynchrounus I/O?

C# How to perform Asynchrounus I/O using Completion Ports with APM-TAP Patterns on WCF Callback?

我正尝试在双工合同中使用 WCF 回调来利用 I/O 完成端口。我正在使用以下简单的行来执行此操作:

OperationContext.Current.OnPushData(data);

其中OnPushData是在客户端实现的回调合约操作
由于此行表示使用某些网络接口的响应(输出操作),并且 WCF 也依赖于 ThreadPool 可用作工作程序的线程线程或 I/O CompletionPortThread,通过使用 TAP 或 APM 模式写入完成端口来利用 I/O CompletionPortThreads 是个好主意(正如我提到的文章建议)而不是使用普通的工作线程,这将大大提高性能。

简答:
能够将 Async I/O 与 Duplex WCF Contract 一起使用的技巧是以下简单代码:

    [OperationContract(IsOneWay = true)]
    Task OnPushData(data);

只是您需要将回调合约方法的 return 类型更改为 Task。但这还不够,您需要像这样实现 async 方法

    public async Task PublishData()
    {
        communicationCallback = (ICommunicationObject)service.Callback;
        if (communicationCallback.State == CommunicationState.Opened)
        {
                await service.Callback.OnPushData(data);
        }
    }

仅此而已。 这实际上提高了我的应用程序的性能。现在我可以看到 I/O 完成端口线程利用调用 ThreadPool.GetAvailableThreads(workers,IO)

一些解释:
据我了解,要能够使用 Async I/O 机制,您需要执行以下操作:

1- 确定您的 I/O 操作。
2- 一种封装异步 I/O 逻辑的方法。
3- 当async I/O 完成时将调用的回调机制,其目的主要是获取Async I/O.
的结果 4- 将保存异步 I/O 结果的对象。

.NET framework 提供了 3 种设计模式:

1- IAsyncResult 异步模式: 其中 BeginxxxEndxxx 将封装您的异步逻辑以及代表回调方法的 Callback Delegate,当然还有用于保存异步 I/O 结果的 IAsyncResult 对象。
2- 基于任务的异步模式:仅使用一个class,即Task和async/await关键字,方便使用TAP 模式。
3- 基于事件的异步模式。

您可以在 How to Implement an Asynchronous Service Operation

阅读更多关于如何将这些模式与 WCF 服务结合使用的信息

然而,之前的 link 非常适合实现异步 request/response 服务,但是没有解释如何使用回调契约来实现。
不幸的是,在我的例子中,我必须使用 WCF 框架实现 subscriber/publisher 模式,其中服务端定期(每 1 秒)启动数据发布。

更多详情:
我会尽量缩短它:
WCF 依赖于 .NET Framework 提供的 ThreadPool。 ThreadPool 有两种线程:
1- 工作线程: 用于计算绑定操作。
2- I/O 完成端口线程: 用于获取 I/O 操作的结果。

您必须区分由 CLR 启动的 IOCP 线程和 IOCP 对象。 IOCP Thread 的作用是传递 I/O 操作的结果,而 IOCP Object 是 CLR 发起的接收所有 I/O 请求的对象。换句话说,他们协作实现I/O操作。

您首先需要知道的是,您发出的任何 I/O 请求都会导致一个系统调用,该系统调用将启动一个名为 IRP 的对象(I/O 请求数据包) 无论您使用的是同步范例还是异步范例。

I/O 完成端口 (IOCP) 只不过是一个由 CLR 启动的类队列对象。该对象负责接收所有 I/O 已完成的请求 (IRPs)。此时这里有2种可能性:
1- 您的 I/O 操作由同步方法调用:在这种情况下,调用者线程将被阻塞,直到您的 I/O 操作完成。
2-您的 I/O 操作由异步方法调用:在这种情况下,调用者线程将继续执行,并且在完成之前不会被 I/O 操作阻塞。

假设您正在使用异步方法,当您的异步 I/O 操作完成时,这意味着 IRP 对象已处理,现在它将排队到 IOCP 对象。 ThreadPool IOCP threads会起到从IOCP中拉取相对IRP的作用,将被wrapped在 APM 的 IAsyncResult 或 TAP 的 Task 对象中,并通过 回调机制[=91= 将此对象传递到您的应用程序级别].

部分参考资料:

[1]: https://msdn.microsoft.com/en-us/library/ms734701.aspx
[2]: http://blog.stephencleary.com/2012/08/async-wcf-today-and-tomorrow.html
[3]: http://southworks.com/blog/2013/10/29/asynchronous-io-in-c-io-completion-ports/
[4]: http://southworks.com/blog/2013/08/02/asynchronous-io-in-c-introduction/
[5]: http://mikehadlow.blogspot.com/2011/03/7000-concurrent-connections-with.html
[6]: https://msdn.microsoft.com/en-us/library/ms731177(v=vs.110).aspx
[7]: http://www.amazon.es/Clr-Via-C-Developer-Reference/dp/0735667454