我需要的是一个按顺序执行异步操作的类。
class FooSocket
{
private Socket _Socket;
// Message is a class that wraps a byte array.
public Task<Message> Receive() { /*Bla...*/ };
public Task<int> Send(Message message) { /*Bla...*/ };
}
如果我按此顺序呼叫发送,接收和发送,我需要先发送并排队剩余的接收和发送操作,直到第一次接收完成。
我尝试在课堂上创建一个主要任务字段,并遵循MainTask = MainTask.ContinueWith(...)
方法。我甚至写了一个名为Sequencer的类,它确实做到了这一点,但它在某种程度上感觉不对,在continuation和stuff中创建了嵌套任务(使用Task.Factory.FromAsync方法)。
我还尝试过排队TaskCompletionSource对象并在我的Receive / Send方法中返回它们的任务,在一个单独的线程上以无限循环检查队列,但由于我将拥有大约200k的FooSocket实例,每个人也觉得不明智。如果我把它作为一个线程池,我来到这个“线程池不应该用于长时间运行的操作”规则。
我感觉很亲密,但无法确定订购这些工作的最有效方式是什么。
答案 0 :(得分:2)
我会使用TPL Dataflow。您可以将其安装为via NuGet,也可以将其作为Async CTP的一部分进行安装。 TPL Dataflow提供基本BufferBlock<T>
类型,听起来就像您需要的那样。
如果您只是对套接字进行建模,那么在缓冲数据时将完成Send
任务,继续读入另一个缓冲区,并在读取时完成Receive
任务缓冲。 (注意:Socket
上的“发送”操作在数据缓冲到操作系统时完成,而不是在线路上或到达目的地时完成。
如果您正在为更高级别的命令/响应建模,那么您应该有一个代表整个命令/响应的任务,正如James建议的那样。我会两个都做;通过async
/ await
支持,可以轻松地将其中一个分层。 (注意:Socket
上的“接收”操作可以通过部分接收完成,因此您需要message framing。
您的架构也可能需要一些工作:
我将拥有大约200k的FooSocket实例
这肯定是个问题(我假设您正在使用TCP / IP)。默认情况下只有~65K TCP / IP端口,其中只有~16K是短暂的,你必须为操作系统留下大量的“喘息空间”或者它开始行为不端。我估计只有~12K的连接是现实的,除非你改变短暂的范围,理论上可以达到~59K。 〜200K是不可能的 - 除非您更改短暂范围和具有多个带有负载均衡器的IP地址。
答案 1 :(得分:1)
如果它是请求/响应类型的行为,恕我直言,任务粒度应该是一个完整的往返,而不是分开发送和接收。
您不需要CTP for .net 4支持,您可以使用异步定位包。
消费代码是什么样的?一个等待调用的循环?