在过去的几年中,我使用异步编程模型和套接字开发了客户机/服务器软件。MSDN上的这个示例虽然与ManualResetEvents等同步机制过于复杂,但说明了概念:您使用BeginXXX()和EndXXX()方法对进行连接和流操作。
这样做的好处是让线程池根据需要分配线程(例如,当接收到数据时),而不是每个连接都有一个专用线程,这不会扩展。
最近有人提到,这种方法也可以使用.NET 4.5中引入的异步/等待模型来实现,从而使用任务并使APM在此场景中变得不必要。这是怎么做的?
发布于 2015-01-18 11:28:58
Task Asynchronous Pattern及其所使用的关键字async-await允许您使用异步I/O (正如您所说的),但可以使用“更干净”的方式。
与使用BeginXXX和EndXXX方法以及在彼此之间传递回调不同,您可以简单地在返回awaitable的异步方法上使用await (A Task就是其中的一个例子)。
例如,让我们使用HttpClient创建一个示例
public async Task DoGetWebRequestAsync()
{
var httpClient = new HttpClient();
await httpClient.GetAsync(url);
}这将做的是,一旦方法命中await关键字,它将把控制权返回到调用方法,在幕后创建状态机(它将负责执行延续、传播异常等等)。并在IO工作完成后通过IOCP (IO完成端口,由ThreadPool分配)继续工作。
TAP还提供了一种使用TaskFactory.FromAsync将旧的APM模式转换为抽头的方法。
FileInfo fi = new FileInfo(path);
byte[] data = null;
data = new byte[fi.Length];
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read, data.Length, true);
//Task<int> returns the number of bytes read
Task<int> task = Task<int>.Factory.FromAsync(
fs.BeginRead, fs.EndRead, data, 0, data.Length, null);编辑:
如何使用async很简单。例如,使用FileStream
public async Task<byte[]> ReadBufferAsync(string path)
{
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read,
FileShare.Read, data.Length, true);
// Read some bytes, not all, just for the example.
byte[] buffer = new byte[2048];
await fs.ReadAsync(buffer, 0, buffer.Length);
return buffer;
}将方法标记为async,以便在其中使用await关键字,然后在读取的方法上简单地使用await。
发布于 2015-01-19 01:08:06
实际上,Socket类支持的旧APM使用了一个特殊的线程池-- IOCP ("I/O完成端口“)线程池,而不是”在接收数据时“分配线程,而是在启动I/O操作时实际分配线程,但方式允许单个线程(或少量线程…)。例如,只要系统上有内核,就可以处理大量的套接字对象和操作。
至于如何使用新的async/await风格API,不幸的是,Socket类没有得到任何直接的async喜爱。然而,所有的包装都做到了。最直接的替代方法是使用NetworkStream类,并使用ReadAsync()和WriteAsync(),这是一种很好的方法。
如果您仍然想直接使用Socket API (本质上),您必须自己用一个可使用的实现包装它。IMHO是一个非常好的资源,它解释了一种可能的方法:等待套接字操作
https://stackoverflow.com/questions/28008978
复制相似问题