Supposons que j'écris un code de proxy TCP. Je lis à partir du flux entrant et de l'écriture au flux de sortie. Je sais que Stream.Copy utilise un tampon, mais ma question est la suivante: Est-ce que la méthode Stream.copy écrit au flux de sortie lors de la récupération du prochain bloc du flux d'entrée ou d'une boucle comme "Lire le morceau de la saisie, écrivez le morceau à partir de l'entrée, etc."? p>
4 Réponses :
L'écriture dans le flux de sortie est impossible (lors de l'utilisation d'un tampon) tout en récupérant le prochain chunk, car la récupération du morceau suivant peut écraser le tampon tout en étant utilisé pour la sortie.
Vous pouvez dire utiliser un double tampon, mais sa pareille la même chose que d'utiliser un tampon à double taille. P>
Depuis (comme vous le note vous-même), nous pouvons utiliser un tampon séparé (ou un fragment de tampon), il n'est clairement pas «impossible».
Selon le réflecteur, il ne le fait pas. Ce comportement est mieux documenté car il introduirait la concurrence. Ceci n'est jamais sûr à faire en général. De sorte que la conception de l'API n'est pas "pipe" est sonore. P>
Ce n'est donc pas simplement une question de flux.copy code> étant plus ou moins intelligente. La copie de manière concomitante n'est pas un détail de mise en œuvre. P>
flux.copy est une opération synchrone. Je ne pense pas qu'il soit raisonnable de s'attendre à ce qu'il utilise une lecture / écriture asynchrone pour faire une lecture simultanée et écrire. p>
Je m'attendrais à ce que j'attendrais une version asynchronise (comme randomAccesstream.copyasync a>) utiliser simultanément lire et écrire. p>
REMARQUE: L'utilisation de threads multiples pendant la copie serait un comportement indésirable, mais en utilisant la lecture et l'écriture asynchrones pour les exécuter en même temps, c'est d'accord. P>
L'asynchrone n'implique pas la concurrence. Aller simultanément avec une documentation appropriée et être très explicite à ce sujet serait très dangereux. Presque rien n'est le fil-en sécurité par défaut.
@usr, pas sûr de ce que votre commentaire est à propos de ... peut-être une utilisation confusion de "parallèle"? Voir Modifier (parallèle -> simultané).
Sry, mon commentaire n'était pas clair. Se référant à ceci: "Je m'attendrais à une version asynchronée ... à ... lire et écrire simultanément.": RandomAccessstream.copyasync ne peut pas le faire simultanément car cela introduirait potentiellement des conditions de course dans le code des utilisateurs /-cadre. Les deux lues et l'écriture pourrait accéder à une variable partagée ou telle.
@USR Quelles conditions de race? Je serais très surpris si un flux ne prend en charge que les opérations de lecture / écriture asynchronisation (Beginxxx / endxxx paire de XXXASYNC pour 4.5) les impernerait explicitement à avoir des conditions de course. Maintenant, pour le code de l'utilisateur - l'opération asynchrone rappellera le même thread qu'il a été lancé, pas de problèmes de concurrence ici. Le seul problème immédiat que je peux voir si le même tampon est utilisé pour la désinténation ou la lecture et la source d'écriture, mais il n'est qu'un problème si celui qui appelle les méthodes d'Asynchronos les partage explicitement ...
Les appels de lecture et d'écriture peuvent exécuter sur une implémentation sur le flux personnalisé. Ils pourraient par exemple incrémenter une variable "statique int Readwritecount". Si appelé simultanément une course existe. Encore une fois: l'asynchronie n'implique pas le parallélisme. Pour cette raison, les appels de lecture et d'écriture ASYNC ne doivent pas être thread-sécurité en interne. Ils pourraient s'attendre à courir sur un fil à la fois (bien que sur différents fils au fil du temps).
@usr, je suppose que nous discutons tous les deux exactement la même chose - il n'y a pas de mot qui décrit "2 opérations exécutées en même temps i> sur le même thread" (comme dans le cas du début de Bekread et des opérations de BeginWrite après l'autre dans le code). Ou je manque quelque chose à nouveau?
Voici la mise en œuvre de afin que vous puissiez le voir, il se lit à partir de la source, alors em > Écrit à la destination. Cela pourrait probablement être amélioré;) p> edit: em> Voici une implémentation possible d'une version de tuyautée: p> Donc, apparemment, cela n'apporte aucun avantage, ce qui est probablement la raison pour laquelle il n'est pas implémenté de cette façon ... p> p> copyto code> in .NET 4.5:
public static void CopyToPiped(this Stream source, Stream destination, int bufferSize = 0x14000)
{
byte[] readBuffer = new byte[bufferSize];
byte[] writeBuffer = new byte[bufferSize];
int bytesRead = source.Read(readBuffer, 0, bufferSize);
while (bytesRead > 0)
{
Swap(ref readBuffer, ref writeBuffer);
var iar = destination.BeginWrite(writeBuffer, 0, bytesRead, null, null);
bytesRead = source.Read(readBuffer, 0, bufferSize);
destination.EndWrite(iar);
}
}
static void Swap<T>(ref T x, ref T y)
{
T tmp = x;
x = y;
y = tmp;
}
MemoryStream code> S, je ne m'attendais pas à une amélioration significative, car elle n'utilise pas les ports d'achèvement de l'IO (AFAIK); et en effet, la performance est presque identique li>
Je crois que la taille du tampon joue un rôle important lors de l'utilisation de fichiers.
@Israellot, oui, probablement. La taille de la mémoire tampon par défaut que j'ai utilisée est la même que dans le flux par défaut.copie.
La solution idéale serait d'alterner deux tampons: Stackoverflow.com/a/4139427/648265
@ivan_pozdeev, votre édition dans mon code était incorrecte, il a provoqué une mémoire tampon vide dans le flux de sortie. Je l'ai retourné. S'il vous plaît ne faites pas d'importantes modifications avec le code des autres personnes, à moins que ce ne soit juste pour corriger une erreur de syntaxe ou une typo évidente.
@Thomaslevesque: écrire 0 octets devrait être un non-OP - qu'est-ce qui ne va pas avec ça?
@Thomaslevesque: Je n'ai tout simplement pas aimé la référence jonglant. La technique de l'index de matrice de style C semble plus rationalisée.
Question interessante; Je ne sais pas réellement sans vérifier. Bien sûr, il convient de noter que cela nécessiterait que cela nécessiterait 2 tampons distincts (ou deux parties séparées d'un seul tampon).
Oui, il est assez évident qu'un double tampon est nécessaire. Mais je ne suis pas sûr que la fonction flux.copy est celle intelligente.
Il convient de noter que s'il utilisait un tuyau, il ferait ensuite deux copies de flux, ce qui impliquerait alors des deux autres tuyaux, qui ...