Плохая производительность распаковки GZipStream - PullRequest
5 голосов
/ 05 октября 2009

У меня есть приложение .NET 2.0 WinForms, которое подключается к внутреннему WAS-серверу. Я использую GZipStream для декодирования данных, возвращающихся из вызова HttpWebRequest на сервер. Возвращенные данные являются сжатыми CSV, которые Apache сжимает. Весь стек сервера находится в Hibernate -> EJB -> Spring -> Apache.

Для небольших ответов производительность в порядке (<50 мс). Когда я получаю ответ> 150 КБ, требуется более 60 секунд для распаковки. Кажется, что большую часть времени проводят в конструкторе GZipStream.

Это код, показывающий, где я получаю поток ответов от вызова HttpWebResponse:

using (Stream stream = this.Response.GetResponseStream())
{
 if (this.CompressData && this.Response.ContentEncoding == "gzip")
 {
        // Decompress the response
  byte[] b = Decompress(stream);
  this.ResponseBody = encoding.GetString(b);
    }
 else
 {
  // Just read the stream as a string
  using (StreamReader sr = new StreamReader(stream))
  {
   this.ResponseBody = sr.ReadToEnd();
  }
 }
}

Редактировать 1

Исходя из комментария от Lucero, я изменил метод Decompress следующим образом, но я не вижу какого-либо выигрыша в производительности от загрузки ResponseStream в MemoryStream до создания экземпляра GZipStream.

private static byte[] Decompress(Stream stream)
{
 using (MemoryStream ms = new MemoryStream())
 {
  byte[] buffer = new byte[4096];
  int read = 0;

  while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
  {
   ms.Write(buffer, 0, read);
  }

  ms.Seek(0, SeekOrigin.Begin);

  using (GZipStream gzipStream = new GZipStream(ms, CompressionMode.Decompress, false))
  {
   read = 0;
   buffer = new byte[4096];

   using (MemoryStream output = new MemoryStream())
   {
    while ((read = gzipStream.Read(buffer, 0, buffer.Length)) > 0)
    {
     output.Write(buffer, 0, read);
    }

    return output.ToArray();
   }
  }
 }
}

Исходя из приведенного выше кода, кто-нибудь может увидеть какие-либо проблемы? Мне это кажется довольно простым, но это сводит меня с ума.

Редактировать 2

Я профилировал приложение, используя ANTS Profiler, и в течение 60-х годов декомпрессии ЦП приближался к нулю и использование памяти не менялось.

Редактировать 3

Фактическое замедление происходит во время чтения

this.Response.GetResponseStream
Все 60 секунд тратятся на загрузку потока ответов в MemoryStream. Как только он появится, вызов GZipStream будет быстрым.
Редактировать 4

Я обнаружил, что при использовании HttpWebRequest.AutomaticDecompression возникает та же проблема с производительностью, поэтому я закрываю этот вопрос.

Ответы [ 4 ]

1 голос
/ 06 октября 2009

DotNetZip имеет класс GZipStream, который можно использовать в качестве замены для System.IO.Compression.GZipStream.

DotNetZip бесплатен.

NB. Если вы используете только GZipStream, вам нужен файл Ionic.Zlib.dll, а не Ionic.Zip.dll.

1 голос
/ 05 октября 2009

Попробуйте сначала загрузить данные в MemoryStream, а затем распаковать MemoryStream ...

0 голосов
/ 23 августа 2012

Я опущу свои три цента на эту тему, просто чтобы уведомить пользователей C # о том, что 7Zip, похоже, представляет свой API на простом C #. Я думаю, что вы все хорошо знаете инструмент 7Zip, и, по крайней мере, для меня, независимо от того, насколько хорошо или плохо спроектирован его API, - зная, что это очень помогает с точки зрения повышения производительности обработки файлов / потоков ZIP.

ref: http://www.splinter.com.au/compressing-using-the-7zip-lzma-algorithm-in/

0 голосов
/ 06 октября 2009

Извините, что не ответил на ваш вопрос напрямую, но вы уже смотрели SharpZip? Я нашел, что это намного проще в использовании, чем Gzip. Если у вас возникли проблемы с решением вашей текущей проблемы, возможно, он лучше справится с этой задачей.

http://www.icsharpcode.net/OpenSource/SharpZipLib/

...