Remplacement de Socket.ReceiveAsync par NetworkStream.ReadAsync (awaitable)
J'ai une application qui fait quelques centaines de connexions TCP en même temps, et reçoit un flux constant de données.
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); }
}
Mes tentatives ont conduit à quelque chose comme ceci:
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);
}
}
Le problème que j'ai eu a été la méthode d'appel StartReceive()
serait de les bloquer, et de ne pas obtenir à l'accompagnement StartSend() method called after
StartReceive(). Creating a new task for
StartReceive()would just end up with 300-ish threads, and it seems to do so just by calling
StartReceive()` de toute façon.
Quelle serait la bonne méthode de la mise en œuvre de la nouvelle async
et await
les mots clés sur mon code existant lors de l'utilisation d'un NetworkStream
de sorte qu'il utilise le pool de threads que Socket.SendAsync()
et Socket.ReceiveAsync()
sont utilisation afin d'éviter d'avoir des centaines de threads/tâches?
Est-il un avantage de performance de l'aide networkstream
de cette manière plus de i/o ports de fin avec beginreceive
?
source d'informationauteur Josh
Vous devez vous connecter pour publier un commentaire.
Vous êtes de changer deux choses à la fois: l'asynchrone style (
SocketAsyncEventArgs
àTask
/async
) et le niveau d'abstraction (Socket
àNetworkStream
).Puisque vous êtes déjà à l'aise avec
Socket
je recommande simplement de changer le asynchrones style, et de continuer à utiliser leSocket
classe directement.La Async CTP ne donne pas
Socket
toutasync
méthodes compatibles avec (ce qui est bizarre; je suppose qu'ils ont été laissés de côté par erreur et sera ajouté dans .NET 4.5).Il n'est pas difficile de créer votre propre
ReceiveAsyncTask
méthode d'extension (et similaires, en emballages pour d'autres opérations) si vous utilisez mon AsyncEx bibliothèque:Une fois que vous faites cela, votre
StartReceive
peut être écrite comme suit:Maintenant, pour répondre à de nombreux points mineurs:
await
ne pas générer un nouveau thread. J'ai écrit jusqu' un async/await intro sur mon blogcomme beaucoup d'autres.async
/await
permet la simultanéité, mais cela n'implique pas nécessairement le multithreading.async
/await
n'est pas une marque nouvelle forme de traitement asynchrone, c'est juste une moyen plus facile à express traitement asynchrone. Il utilise toujours IOCPs dessous.async
/await
a légèrement plus bas que le niveau inférieur méthodes; son appel, c'est la facilité de l'écriture et de la composition de méthodes asynchrones.async
/await
. Stephen Toub sur le Parallèle de l'Équipe écrit quelques exemple de socket spécifique awaitables qui peut aider avec ce problème. (Je recommande d'utiliser le modèle simple d'abord, et seulement à l'aide de la performance-approche améliorée si vous trouvez qu'il est nécessaire; encore, il est bon de savoir qu'elle est là, si vous finissez par avoir besoin d'elle).Task
à moins que vous vraiment besoin à retournervoid
.Task
est awaitable, de sorte que votre méthode est modulable (et plus facilement testables);void
est plus comme "fire and forget".ConfigureAwait(false)
pour informer le reste de laasync
méthode à exécuter sur un thread du pool. - Je l'utiliser dans mon exemple ci-dessus, de sorte queProcessData
est exécutée dans un thread du pool, tout comme il l'a été lors de l'utilisation deSocketAsyncEventArgs
.Socket.Connected
est inutile. Vous avez besoin d'envoyer des données afin de détecter si la connexion est toujours valide.