Я пытаюсь реализовать 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 с тем же кодом под моно.
Вероятно, единственным более быстрым вариантом было бы использование небуферизованного ввода-вывода
: Функция ReadFile , Функция CreateFile , Функция WriteFile с флагом FILE_FLAG_NO_BUFFERING
с буфером 2–6 МБ.
Также таким образом вам придется согласовать размер буфера с размером сектора файловой системы и т. Д.
Это будет значительно быстрее - особенно в Windows XP.
кстати. Таким образом я получил полосу пропускания ~ 400 МБ на чередующемся массиве RAID 0 (с использованием буфера 4 МБ).
Вы пробовали меньший размер буфера? Размер буфера в 1 МБ ужасно огромен, и обычно размер буфера от 4 до 64 КБ обеспечивает наилучшую производительность.
Кроме того, это может быть связано с вашим вопросом: Как написать код сверхбыстрой потоковой передачи файлов на C #?
И, возможно, вы можете повысить производительность, используя файлы с отображением в память: http: // weblogs.asp.net/gunnarpeipman/archive/2009/06/21/net-framework-4-0-using-memory-mapped-files.aspx
Есть обычные подозрения в увеличении скорости по сети:
Кроме того, вы находитесь в милость ваших аппаратных ограничений.
File.Copy()
просто вызывает CopyFile()
API, вы можете попробовать p/invoke SHFileOperation()
, который использует shell - это часто кажется быстрее.
Для более глубокого понимания вариантов дизайна и компромиссы, связанные с копированием файлов, с общими сетевыми ресурсами и без них, я предлагаю вам взглянуть на запись в блоге Марка Руссиновича пару лет назад. Есть еще много проблем, помимо размеров секторов жесткого диска, например ...
Попробуйте изменить размер буфера, чтобы он был равен размеру сектора на жестком диске - скорее всего, 4 Кб. Также используйте класс System.Diagnostics.Stopwatch для определения времени.
Я бы также не стал использовать методы async в узком цикле - это повлечет за собой некоторые накладные расходы, связанные с выходом и выделением потока из пула для выполнения работы.
Опять же, используйте оператор using
для управления утилизацией ваших потоков. Обратите внимание, однако, что это исказит ваше время, поскольку в настоящее время вы избавляетесь от объектов после остановки таймера.