2013-07-18 3 views
0

У меня есть приложение, которое загружает файлы с FTP-сервера Unix. Он работает нормально, просто проблема с этой производительностью: файлы размером < = 1K загружаются в среднем между 2084 и 2400 миллисекундами для скачивания, тогда как приложения, такие как Filezilla, загружают одни и те же файлы менее чем за 1 секунду (за каждый файл).C# ftpwebrequest performance

Возможно, на этот раз это нормально для некоторых обычных пользователей, но неприемлемо для моего приложения, так как мне нужно загрузить THOUSANDS файлов.

Я оптимизирую код столько, сколько мог: - Кэш и буфер для чтения содержимого создаются 1 раз в конструкторе класса. - Я создаю 1 раз учетные данные сети и повторно использую каждую загрузку файла. Я знаю, что это работает, потому что для первого файла он загружается как 7s, а все последующие загрузки находятся в диапазоне от 2s. - Я изменяю размер буфера от 2K до 32K. Я не знаю, поможет ли это или нет, поскольку файлы Im загружаются меньше 1K, поэтому теоретически буфер будет заполняться всей информацией в 1 раунде из сети.

Возможно, это не связано с сетью, но к тому, как Im пишет и/или окна обрабатывает запись файла?

Может кто-нибудь, пожалуйста, дайте мне несколько советов о том, как сократить время на что-то похожее на filezilla ?? Мне нужно сократить время, в противном случае мой ftp будет работать в течение 3 дней 24 часа в сутки, чтобы завершить свою задачу :( Большое спасибо заранее. Код здесь: Его не полный, он просто показывает загружаемую часть.

//Create this on the constructor of my class 
downloadCache = new MemoryStream(2097152); 
downloadBuffer = new byte[32768]; 

public bool downloadFile(string pRemote, string pLocal, out long donwloadTime) 
{ 
FtpWebResponse response = null; 
Stream responseStream = null; 

try 
{ 
    Stopwatch fileDownloadTime = new Stopwatch(); 
    donwloadTime = 0; 
    fileDownloadTime.Start(); 

    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(pRemote); 
    request.Method = WebRequestMethods.Ftp.DownloadFile; 
    request.UseBinary = false; 
    request.AuthenticationLevel = AuthenticationLevel.None; 
    request.EnableSsl = false; 
    request.Proxy = null; 
    //I created the credentials 1 time and re-use for every file I need to download 
    request.Credentials = this.manager.ftpCredentials; 

    response = (FtpWebResponse)request.GetResponse(); 
    responseStream = response.GetResponseStream(); 

    downloadCache.Seek(0, SeekOrigin.Begin); 
    int bytesSize = 0; 
    int cachedSize = 0; 

    //create always empty file. Need this because WriteCacheToFile just append the file 
    using (FileStream fileStream = new FileStream(pLocal, FileMode.Create)) { }; 

    // Download the file until the download is completed. 
    while (true) 
    { 
     bytesSize = responseStream.Read(downloadBuffer, 0, downloadBuffer.Length); 
     if (bytesSize == 0 || 2097152 < cachedSize + bytesSize) 
     { 
      WriteCacheToFile(pLocal, cachedSize); 
      if (bytesSize == 0) 
      { 
       break; 
      } 
      downloadCache.Seek(0, SeekOrigin.Begin); 
      cachedSize = 0; 
     } 
     downloadCache.Write(downloadBuffer, 0, bytesSize); 
     cachedSize += bytesSize; 
    } 

    fileDownloadTime.Stop(); 
    donwloadTime = fileDownloadTime.ElapsedMilliseconds; 

    //file downloaded OK 
    return true; 
} 
catch (Exception ex) 
{ 
    return false; 
} 
finally 
{ 
    if (response != null) 
    { 
     response.Close(); 
    } 

    if (responseStream != null) 
    { 
     responseStream.Close(); 
    } 
} 
} 

private void WriteCacheToFile(string downloadPath, int cachedSize) 
{ 
using (FileStream fileStream = new FileStream(downloadPath, FileMode.Append)) 
{ 
    byte[] cacheContent = new byte[cachedSize]; 
    downloadCache.Seek(0, SeekOrigin.Begin); 
    downloadCache.Read(cacheContent, 0, cachedSize); 
    fileStream.Write(cacheContent, 0, cachedSize); 
} 
} 
+0

Я забыл сказать:.. Im, используя несколько потоков для загрузки нескольких файлов одновременно. – user2232787

ответ

1

Звуки для меня ваша проблема связана с Nagels algorithm используется в клиенте TCP

Вы можете попробовать поворота алгоритма Нагеля от а также установить SendChunked ложь

+0

Спасибо sean717. Я прочитал информацию об алгоритме Nagels. Я также прочитал документацию msdn о том, как отключить это, и он говорит, чтобы установить свойство Socket.NoDelay как true, так и false. Однако это на уровне Socket, а мое приложение использует более высокие классы: FtpWebRequest. Как я могу получить доступ к свойству NoDelay из своего кода? – user2232787

+0

Эй, пожалуйста, взгляните на [этот вопрос] (http://stackoverflow.com/questions/2400949/what-might-cause-the-big-overhead-of-making-a-httpwebrequest-call). В основном FtpWebRequest получен из System.Net.WebRequest, из которого вы можете отключить Nagel. – sean717

+0

Я добавил следующие строки: ServicePoint spTemp = request.ServicePoint; spTemp.UseNagleAlgorithm = false; Мне нужно проверить, работает ли это, поскольку [link] (http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.usenaglealgorithm.aspx) говорит, что «значение этого свойства не влияет существующих объектов ServicePoint. Возникают только новые точки обслуживания, созданные после изменения " – user2232787