Как реализовать производительный filecopy метод в C# от сетевого ресурса?

Я пытаюсь реализовать filecopy метод, который может соответствовать производительности копия, сделанная с Windows Explorer.

Для exemple копия (с Windows Explorer) с нашего nas на мой компьютер, работает выше 100mb/sec.

Моя текущая реализация делает ту же копию приблизительно в 55mb/sec, который уже лучше, чем Система. IO.File. Копия (), который работает в 29mb/sec.

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);
    }

Какая-либо идея, как улучшить производительность?

РЕДАКТИРОВАНИЕ:

Файл читается из основанного на Linux nas с 10 интерфейсами Gigabit Ethernet с 60 диски san позади (не волнуйтесь о его действиях, он работает очень хорошо), и записанный в локальный raid0, который может записать данные приблизительно в 140MB/sec.

Узкое место является гигабитным сетевым интерфейсом места назначения, которого я не могу достигнуть со своим текущим кодом.

Кроме того, удаление записи не сделает чтение немного быстрее, таким образом, я не смогу пойти мимо этого предела чтения 55MB/sec.

РЕДАКТИРОВАНИЕ 2:

Проблема скорости связана с тем, что исходный файл хранится на сетевом ресурсе. Только чтение из моего локального диска с моей частью кода предоставляет мне 112MB/sec скорость.

РЕДАКТИРОВАНИЕ 3:

Samba, кажется, не проблема. Я заменил долю cifs (самба) долей nfs на моем Linux nas и ухудшился результаты, чем с самбой на моем win7 клиенте.

С nfs мой метод копии и Windows Explorer имели ту же производительность вокруг 42MB/sec.

Я вне идей...

РЕДАКТИРОВАНИЕ 4:

Только, чтобы быть уверенными окна были проблемой, я установил debian lenny, смонтировал мою nas nfs канавки и получил 79MB/sec с тем же кодом под моно.

8
задан Altar 8 July 2010 в 17:21
поделиться

6 ответов

Вероятно, единственным более быстрым вариантом было бы использование небуферизованного ввода-вывода : Функция ReadFile , Функция CreateFile , Функция WriteFile с флагом FILE_FLAG_NO_BUFFERING с буфером 2–6 МБ.

Также таким образом вам придется согласовать размер буфера с размером сектора файловой системы и т. Д.

Это будет значительно быстрее - особенно в Windows XP.

кстати. Таким образом я получил полосу пропускания ~ 400 МБ на чередующемся массиве RAID 0 (с использованием буфера 4 МБ).

0
ответ дан 5 December 2019 в 14:00
поделиться

Вы пробовали меньший размер буфера? Размер буфера в 1 МБ ужасно огромен, и обычно размер буфера от 4 до 64 КБ обеспечивает наилучшую производительность.

Кроме того, это может быть связано с вашим вопросом: Как написать код сверхбыстрой потоковой передачи файлов на C #?

И, возможно, вы можете повысить производительность, используя файлы с отображением в память: http: // weblogs.asp.net/gunnarpeipman/archive/2009/06/21/net-framework-4-0-using-memory-mapped-files.aspx

4
ответ дан 5 December 2019 в 14:00
поделиться

Есть обычные подозрения в увеличении скорости по сети:

  • Наличие нескольких потоков загрузки
  • Предварительно выделите блок на диске, где будет находиться файл

Кроме того, вы находитесь в милость ваших аппаратных ограничений.

1
ответ дан 5 December 2019 в 14:00
поделиться

File.Copy() просто вызывает CopyFile() API, вы можете попробовать p/invoke SHFileOperation(), который использует shell - это часто кажется быстрее.

1
ответ дан 5 December 2019 в 14:00
поделиться

Для более глубокого понимания вариантов дизайна и компромиссы, связанные с копированием файлов, с общими сетевыми ресурсами и без них, я предлагаю вам взглянуть на запись в блоге Марка Руссиновича пару лет назад. Есть еще много проблем, помимо размеров секторов жесткого диска, например ...

  • Размер пакета протокола SMB
  • Сколько памяти вы готовы использовать для кэширования (что может замедлить другие процессы)
  • Можете ли вы пожертвовать надежностью ради скорости
  • Хотите ли вы увеличить воспринимаемую скорость или фактическое время до завершения
  • Где и сколько вы хотите кэшировать на нескольких возможных уровнях
  • Заинтересованы ли вы в обеспечении надежной обратной связи и оценок времени
1
ответ дан 5 December 2019 в 14:00
поделиться

Попробуйте изменить размер буфера, чтобы он был равен размеру сектора на жестком диске - скорее всего, 4 Кб. Также используйте класс System.Diagnostics.Stopwatch для определения времени.

Я бы также не стал использовать методы async в узком цикле - это повлечет за собой некоторые накладные расходы, связанные с выходом и выделением потока из пула для выполнения работы.

Опять же, используйте оператор using для управления утилизацией ваших потоков. Обратите внимание, однако, что это исказит ваше время, поскольку в настоящее время вы избавляетесь от объектов после остановки таймера.

5
ответ дан 5 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: