Suggestions pour faire async I / O avec Task Parallel Library
-
26-09-2019 - |
Question
J'ai un code de transfert de fichiers haute performance que j'ai écrit en C # en utilisant le modèle de programmation Async (APM de) langue (par exemple, BeginRead
/ EndRead
). Ce code lit un fichier à partir d'un disque local et l'écrit dans une prise.
Pour de meilleures performances sur le matériel moderne, il est important de garder plus d'une opération d'E / S en attente en vol lorsque cela est possible. Ainsi, je posterai plusieurs opérations de BeginRead
sur le fichier, puis quand on finalise, j'appelle un BeginSend
sur la prise, et quand je fais qui vient compléter une autre BeginRead
sur le fichier. Les détails sont un peu plus compliqué que cela, mais au haut niveau qui est l'idée.
J'ai le travail de code basé APM, mais il est très difficile à suivre et a probablement des bugs subtils de concurrence. J'aimerais utiliser TPL pour cette place. Je me suis dit Task.Factory.FromAsync
ferait à peu près, mais il y a un hic.
Toutes les E / S des échantillons que j'ai vu (plus particulièrement la classe StreamExtensions
dans les extensions parallèles Extras) suppose un contrat de lecture suivie d'une écriture. Cela ne fonctionnera pas I façon besoin.
Je ne peux pas utiliser simplement quelque chose comme Parallel.ForEach
ou l'extension Extras Task.Factory.Iterate
parce que les tâches d'E / S async ne passent pas beaucoup de temps sur un thread de travail, donc parallèle commence juste une autre tâche, entraînant potentiellement des dizaines ou des centaines de en attente des opérations d'E / S; beaucoup trop! Vous pouvez contourner ce problème par Wait
ing vos tâches, mais qui provoque la création d'une poignée d'événement (un objet noyau), et une attente de blocage sur une poignée d'attente des tâches, qui ligote un thread de travail. Ma mise en œuvre sur la base APM évite à la fois de ces choses.
Je joue autour de différentes façons de maintenir les opérations de lecture / écriture multiples en vol, et je l'ai réussi à le faire en utilisant les continuations qui appellent une méthode qui crée une autre tâche, mais il se sent maladroit, et certainement doesn » t sentir comme idiomatiques TPL.
Quelqu'un d'autre aux prises avec un problème comme celui-ci avec le TPL? Toutes les suggestions?
La solution
Si vous êtes inquiet au sujet trop de threads, vous pouvez juste ParallelOptions.MaxDegreeOfParallelism
ensemble à un nombre acceptable dans votre appel à Parallel.ForEach
.