[英]Replacing Socket.ReceiveAsync with NetworkStream.ReadAsync (awaitable)
I have an application that makes a couple hundred TCP connections at the same time, and receives a constant stream of data from them. 我有一个应用程序,它同时生成几百个TCP连接,并从它们接收一个恒定的数据流。
private void startReceive()
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += receiveCompleted;
e.SetBuffer(new byte[1024], 0, 1024);
if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
}
void receiveCompleted(object sender, SocketAsyncEventArgs e)
{
ProcessData(e);
if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
}
My attempts led to something like this: 我的尝试导致了这样的事情:
private async void StartReceive()
{
byte[] Buff = new byte[1024];
int recv = 0;
while (Socket.Connected)
{
recv = await NetworkStream.ReadAsync(Buff, 0, 1024);
ProcessData(Buff,recv);
}
}
The issue I had was the method calling StartReceive()
would block, and not get to the accompanying StartSend() method called after
StartReceive() . Creating a new task for
我遇到的问题是调用
StartReceive()
的方法会阻塞,而不是调用StartReceive()
调用的伴随的StartSend() method called after
. Creating a new task for
. Creating a new task for
StartReceive() would just end up with 300-ish threads, and it seems to do so just by calling
StartReceive()` anyways. . Creating a new task for
StartReceive() . Creating a new task for
would just end up with 300-ish threads, and it seems to do so just by calling
StartReceive()来实现。
What would be the correct method of implementing the new async
and await
keywords on my existing code while using a NetworkStream
so it is using the thread pool that Socket.SendAsync()
and Socket.ReceiveAsync()
are using to avoid having to have hundreds of threads/tasks? 在使用
NetworkStream
,在我现有代码上实现新async
和await
关键字的正确方法是什么,因此它使用Socket.SendAsync()
和Socket.ReceiveAsync()
使用的线程池来避免必须拥有数百个线程/任务?
Is there any performance advantage of using networkstream
in this manner over i/o completion ports with beginreceive
? 以这种方式使用
networkstream
比使用beginreceive
i / o完成端口有任何性能优势?
You're changing two things at once here: the asynchronous style ( SocketAsyncEventArgs
to Task
/ async
) and the level of abstraction ( Socket
to NetworkStream
). 你在这里一次改变两件事:异步样式(
SocketAsyncEventArgs
到Task
/ async
)和抽象级别( Socket
到NetworkStream
)。
Since you're already comfortable with Socket
, I recommend just changing the asynchronous style, and continue using the Socket
class directly. 由于您已经熟悉
Socket
,我建议只更改异步样式,并继续直接使用Socket
类。
The Async CTP doesn't give Socket
any async
-compatible methods (which is weird; I assume they were left out by mistake and will be added in .NET 4.5). Async CTP没有给
Socket
任何async
兼容的方法(这很奇怪;我认为它们被错误地遗漏了,并将在.NET 4.5中添加)。
It's not that hard to create your own ReceiveAsyncTask
extension method (and similar wrappers for other operations) if you use my AsyncEx library : 如果您使用我的AsyncEx库,那么创建自己的
ReceiveAsyncTask
扩展方法(以及其他操作的类似包装器) 并不难 :
public static Task<int> ReceiveAsyncTask(this Socket socket,
byte[] buffer, int offset, int size)
{
return AsyncFactory<int>.FromApm(socket.BeginReceive, socket.EndReceive,
buffer, offset, size, SocketFlags.None);
}
Once you do that, your StartReceive
can be written as such: 完成后,您的
StartReceive
可以这样写:
private async Task StartReceive()
{
try
{
var buffer = new byte[1024];
while (true)
{
var bytesReceived = await socket.ReceiveAsyncTask(buffer, 0, 1024)
.ConfigureAwait(false);
ProcessData(buffer, bytesReceived);
}
}
catch (Exception ex)
{
// Handle errors here
}
}
Now, to address many minor points: 现在,要解决许多小问题:
await
doesn't spawn a new thread. await
不会产生新的线程。 I wrote up an async/await intro on my blog , as have many others. async
/ await
allows concurrency, but that doesn't necessarily imply multithreading. async
/ await
允许并发,但这并不一定意味着多线程。 async
/ await
is not a brand new form of asynchronous processing; async
/ await
不是一种全新的异步处理形式; it's just an easier way to express asynchronous processing. async
/ await
has slightly lower performance than the lower-level methods; async
/ await
性能略低于低级方法; its appeal is the ease of writing and composing asynchronous methods. async
/ await
. async
/ await
时会看到一些GC压力增加。 Stephen Toub on the Parallel Team wrote up some example socket-specific awaitables that can help with that issue. Task
unless you really need them to return void
. Task
除非您确实需要它们返回void
。 Task
is awaitable, so your method is composable (and more easily testable); Task
是可以接受的,因此您的方法是可组合的(并且更容易测试); void
is more like "fire and forget". void
更像是“火与忘”。 ConfigureAwait(false)
to tell the rest of the async
method to execute on a thread pool thread. ConfigureAwait(false)
来告诉其余的async
方法在线程池线程上执行。 I use this in my example above so that ProcessData
is executed in a thread pool thread, just like it was when using SocketAsyncEventArgs
. ProcessData
在线程池线程中执行,就像使用SocketAsyncEventArgs
。 Socket.Connected
is useless. Socket.Connected
没用。 You need to send data to detect if the connection is still valid.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.