2009-08-17 16 views
5

Mam utworzyć aplikację Windows, która rutynowo pobierze plik z serwera równoważenia obciążenia, obecnie prędkość wynosi około 30 MB/s. Jednak próbuję użyć FastCopy lub TeraCopy, który może kopiować z prędkością około 100 MB/s. Chcę wiedzieć, jak poprawić szybkość kopiowania, aby móc szybciej kopiować pliki niż obecnie.Jak sprawić, by mój plik kopii aplikacji był szybszy?

Odpowiedz

4

Jednym z częstych błędów podczas korzystania ze strumieni jest jednoczesne kopiowanie bajtów lub użycie małego bufora. W większości przypadków zapisywanie danych na dysku jest poszukiwaniem, więc użycie większego bufora obniży średni czas wyszukiwania na bajt.

Systemy operacyjne zapisują pliki na dysku w klastrach. Oznacza to, że podczas zapisywania pojedynczego bajtu na dysku system Windows będzie faktycznie zapisywać blok o rozmiarze od 512 bajtów do 64 kb. Możesz uzyskać znacznie lepszą wydajność dysku, używając bufora, który jest wielokrotnością całkowitą 64 kb.

Dodatkowo można zwiększyć wykorzystanie bufora stanowiącego wielokrotność rozmiaru strony pamięci używanego procesora. W przypadku maszyn x86/x64 można ustawić wartość 4 kB lub 4 MB.

Więc chcesz użyć wielokrotności całkowitej równej 4mb.

Dodatkowo, jeśli korzystasz z asynchronicznego IO, możesz w pełni wykorzystać duży rozmiar bufora.

class Downloader 
{ 
    const int size = 4096 * 1024; 
    ManualResetEvent done = new ManualResetEvent(false); 
    Socket socket; 
    Stream stream; 

    void InternalWrite(IAsyncResult ar) 
    { 
     var read = socket.EndReceive(ar); 
     if (read == size) 
      InternalRead(); 
     stream.Write((byte[])ar.AsyncState, 0, read); 
     if (read != size) 
      done.Set(); 
    } 

    void InternalRead() 
    { 
     var buffer = new byte[size]; 
     socket.BeginReceive(buffer, 0, size, System.Net.Sockets.SocketFlags.None, InternalWrite, buffer); 
    } 

    public bool Save(Socket socket, Stream stream) 
    { 
     this.socket = socket; 
     this.stream = stream; 

     InternalRead(); 
     return done.WaitOne(); 
    } 
} 

bool Save(System.Net.Sockets.Socket socket, string filename) 
{ 
    using (var stream = File.OpenWrite(filename)) 
    { 
     var downloader = new Downloader(); 
     return downloader.Save(socket, stream); 
    } 
} 
2

Ewentualnie aplikacja może zrobić wielowątkowości, aby pobrać plik za pomocą wielu wątków, jednak przepustowość jest ograniczona do prędkości urządzeń, które przenoszą treść

1

Najprostszym sposobem jest otwarcie pliku w formacie RAW/binarny tryb (który mówi C nie jest pewien, czy jest odpowiednik C#) i czyta i zapisuje bardzo duże bloki (kilka MB) na raz.

1

Sztuką, z której korzysta TeraCopy, jest asynchroniczne czytanie i pisanie. Oznacza to, że blok danych można zapisać podczas odczytu innego.

Musisz rozejrzeć się za liczbą klocków i rozmiarem bloków, aby uzyskać optymalną dla siebie sytuację. Użyłem tej metody używając C++ i dla nas optymalnym było używanie czterech bloków po 256 KB podczas kopiowania z udziału sieciowego na dysk lokalny.

Pozdrawiam,

Sebastiaan

1

Jeśli prowadzisz Process Monitor można zobaczyć rozmiary bloku, który Eksploratora Windows lub TeraCopy używasz.

W systemie Vista domyślny rozmiar bloku dla sieci lokalnej wynosi 2 MB, co znacznie przyspiesza kopiowanie plików przez ogromną rurę.

0

Po co na nowo odkrywać koło?

Jeśli twoja sytuacja na to pozwala, prawdopodobnie lepiej jest użyć jednego z istniejących "szybkich" narzędzi do kopiowania, niż próbować napisać samemu. Istnieje wiele nieoczywistych przypadków krawędziowych, z którymi należy się uporać, a uzyskiwanie niezmiennie dobrego wykonania wymaga wielu eksperymentów z błędem próbnym.

+0

Czy mogę używać "szybkich" narzędzi do kopiowania dla skryptów (wiersza poleceń)? – Kiquenet

+0

Co najmniej niektóre są skryptowalne - robocopy to jeden z przykładów. – Addys

Powiązane problemy