9
votes

Comment mettre en œuvre une méthode de filecopy performante en C # à partir d'une part de réseau?

J'essaie de mettre en œuvre une méthode de filecopy pouvant correspondre à la performance une copie effectuée avec l'Explorateur Windows.

Pour exemple une copie (avec l'explorateur Windows) de notre NAS à mon ordinateur, effectue plus de 100 Mo. . P>

Mon implémentation actuelle fait la même copie à environ 55 Mo / sec, qui est déjà meilleur que le système.IO.File.copy () qui fonctionne à 29 Mo / sec. P>

static void Main(string[] args)
    {
        String src = @"";
        String dst = @"";

        Int32 buffersize = 1024 * 1024;
        FileStream input = new FileStream(src, FileMode.Open, FileAccess.Read, FileShare.None, 8, FileOptions.Asynchronous | FileOptions.SequentialScan);
        FileStream output = new FileStream(dst, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8, FileOptions.Asynchronous | FileOptions.SequentialScan);

        Int32 readsize = -1;
        Byte[] readbuffer = new Byte[buffersize];
        IAsyncResult asyncread;
        Byte[] writebuffer = new Byte[buffersize];
        IAsyncResult asyncwrite;

        DateTime Start = DateTime.Now;

        output.SetLength(input.Length);

        readsize = input.Read(readbuffer, 0, readbuffer.Length);
        readbuffer = Interlocked.Exchange(ref writebuffer, readbuffer);

        while (readsize > 0)
        {
            asyncwrite = output.BeginWrite(writebuffer, 0, readsize, null, null);
            asyncread = input.BeginRead(readbuffer, 0, readbuffer.Length, null, null);

            output.EndWrite(asyncwrite);
            readsize = input.EndRead(asyncread);
            readbuffer = Interlocked.Exchange(ref writebuffer, readbuffer);
        }

        DateTime Stop = DateTime.Now;

        TimeSpan Duration = Stop - Start;
        Double speed = input.Length / Duration.TotalSeconds; // bytes/s

        System.Console.WriteLine("MY Speed : " + (speed / 1024 / 1024).ToString() + " mo/sec");

        input.Close();
        output.Close();
        System.IO.File.Delete(dst);
    }


3 commentaires

Windows Explorer peut également exploiter le cache du système de fichiers et afficher un transfert de 100 Mo / SEC, mais le noyau peut ne pas avoir écrit le fichier entier sur le disque, ce faisant ainsi en arrière-plan une fois l'opération terminée. À quelle vitesse pouvez-vous lire le fichier entier dans une mémoire Morthstream?


Est-ce vraiment 100 Mbps ou 100 Mbps (grande différence là-bas)? Si c'est 100 MBPS, c'est un NAS assez rapide. Utilisez également system.diagnostics.stopwatch pour mesurer le temps écoulé avec précision.


1 °) En aucun cas. Le fichierize est de 19 Go et l'unité n'a que 8 Go de mémoire. En outre, la destination RAID0 peut prendre beaucoup plus de 100 Mo / SEC, le goulot d'étranglement ici est l'interface réseau Gigabit. 2 °) C'est un NAS très rapide :) Selon le repère, nous avons fait, il peut livrer entre 1200 et 1400 mbytes par seconde en lecture séquentielle.


6 Réponses :


5
votes

Essayez de changer la taille du tampon pour égaler la taille du secteur sur le disque dur - probable 4 Ko. Utilisez également la classe System.Diagnostics.stopwatch pour le moment chronométrage.

Je n'aurais pas non plus la peine d'utiliser les méthodes asynchrones dans une boucle serrée - elle entraînera une augmentation des frais généraux et alloue un fil de la piscine pour faire le travail.

Encore une fois, utilisez le à l'aide de la relève pour gérer la disposition de vos flux. Notez cependant que cela inclinera votre synchronisation car vous disposez actuellement des objets après avoir arrêté la minuterie.


3 commentaires

Les petits multiples de tailles sectorielles fonctionnent également bien ... Testez tout de 1x à 16 fois peut montrer un gain important dans l'un d'entre eux.


Fais seule une lecture synchrone n'a fourni aucune meilleure performance.


Je ne suis pas sûr de lire à partir du flux et de l'écriture à un autre courant de manière asynchrone en même temps, c'est plus rapide non plus. Vous seriez biché des E / S avec deux tâches en même temps. Pour les fichiers plus petits, avez-vous essayé de lire le lot dans la RAM puis de l'écrire? De plus, vous pouvez écrire dans des morceaux de gros morceaux ou tous à la fois, la tampon n'est donc pas strictement nécessaire.



1
votes

Il existe des suspects habituels pour augmenter la vitesse sur un réseau:

  • avoir plusieurs threads de téléchargement
  • Pré-allouez le bloc sur le disque où le fichier réside

    Autre que cela, vous êtes à la merci de vos limitations matérielles.


2 commentaires

Plusieurs threads de téléchargement ne fonctionnaient que si le goulot d'étranglement n'était pas l'E / S, ce qui est probablement.


@Adam - Ce pourrait être le réseau, auquel cas il serait capable d'augmenter légèrement la perfection. Comme pour tout ce qui est lié à Perf, cependant, il s'agit de tester et de mesurer les différentes techniques.



4
votes

Avez-vous essayé plus petit tailles de tampon? Une taille tampon de 1 Mo est terriblement énorme et normalement tampon de 4-64kb vous donne la meilleure performance.

En outre, cela peut être lié à votre question: Comment écrire un code de diffusion de fichiers super-rapide en C #?

Et peut-être que vous pouvez améliorer les performances à l'aide de fichiers mappés de mémoire: http://weblogs.asp.net/gunnarpeipman/archive/2009/06/21/net-Framework-4-0-Autilisateur-Memory-Memory-Files-Files. ASPX


3 commentaires

L'utilisation d'une taille de tampon de 64 kb rend la copie aller plus lente d'environ 46 Mo / sec.


Donc, jusqu'à 2 Mo, 4 Mo, ou plus Augmente Performancefurther? La performance augmente-t-elle de 64 à 128? Peut-être qu'il y a un beespot entre 64k et 1MB où la performance est optimale?


Après 256kb, il ne semble pas y avoir d'augmentation de la performance, toujours environ 60 Mo / sec.



1
votes

fichier.copy () appelle simplement le fichier copyfile () API, vous pouvez essayer p / invoke shfileoperation () qui est ce qui est quoi la coque utilise - il semble souvent plus rapide.


1 commentaires

Cela pourrait être une option si je copie seulement un fichier, mais je dois également être capable d'écrire la sortie sur plusieurs destinations.



1
votes

Pour une compréhension plus profonde des options de conception et des compromis impliqués dans la copie de fichiers, avec et sans actions réseau, je vous suggère de regarder Mark Russinovich's Blog Post Il y a quelques années. Il y a beaucoup plus de rides impliquées que de la tailles du secteur du disque dur, par exemple ...

  • La taille du paquet du protocole SMB
  • Quelle mémoire vous êtes prêt à utiliser pour la mise en cache (qui peut ralentir d'autres processus)
  • si vous pouvez sacrifier la fiabilité de la vitesse
  • si vous souhaitez augmenter la vitesse perçue ou le temps réel - jusqu'à la fin de la finition
  • Où et combien vous voulez mettre en cache à plusieurs niveaux possibles
  • si vous êtes intéressé à fournir des devis fiables et des estimations de temps

0 commentaires

0
votes

probablement la seule option plus rapide utiliserait un absorbé IO : Fonction ReadFile , Fonction CreateFile , Fonction Writefile avec le File_flag_no_buffering drapeau avec 2-6 MB tampon.

De cette façon, vous devez aligner la taille de la mémoire tampon avec la taille du secteur du système de fichiers, etc.

Ce serait nettement plus rapide - surtout dans Windows XP.

BTW. J'ai atteint ~ 400 Mo de bande passante sur un tableau à rayures 0 de cette façon (en utilisant 4 Mo tampon).


3 commentaires

Comment l'aide d'E / S désolérait-elle avec le stockage NAS? Les coûts d'accès au réseau et de disque dur domineraient. L'élimination de la mémoire tampon pourrait très bien ralentir les performances, lorsque plusieurs goulots d'étranglement sont présents.


Je n'ai pas remarqué la partie NAS. Vous n'éliminez que la mise en mémoire tampon automatique par le système. Vous tamponnez toujours les données mais vous choisissez la taille de la mémoire tampon. Pour les disques lents, cela n'a pas beaucoup, mais pour les matrices RAID rapides et les réseaux de tubercules de la performance absorbée IO sont très perceptibles - sans parler de cela est facile sur la CPU. Je ne l'utilise pas si je n'ai pas besoin de la manipulation de Winapi. Quoi qu'il en soit, vous pouvez utiliser IO non coupé avec NAS.


Après avoir finalement été entré dans le lapin entier (chevauchement + IO non coupé), je peux confirmer que c'est le seul moyen d'obtenir de véritables performances. Vous avez 2,25 gibr / sec sur un lien Dual 10g (Merci SMB3) lors de la lecture d'une échelle NAS.