使用AsciiEncoding.GetBytes和Convert.FromBase64String编写解码字节时FileStream.Write中的性能问题

时间:2009-05-15 06:16:19

标签: c# .net encoding filestream decoding

使用FileStream.Write函数时遇到性能问题。

我有一个控制台应用程序,用于使用StreamReader对象从文件中读取Base64字符串(~size为400 KB)。我使用Convert.FromBase64String将此字符串转换为字节数组。然后我使用FileStream对象将此字节数组写入文件。这里获得的字节数组长度为334991。

我测量了写入字节数组所花费的时间 - 它大约是 0.116秒。

为了好玩,我使用ASCIIEncoding.GetBytes函数从相同的Base64编码字符串中获取了字节数组(尽管我知道这不会给出正确的DECODED输出 - 我只是想尝试一下)。我使用FileStream对象将此字节数组写入文件。这里获得的字节数组长度为458414。

我测量了使用这种方法编写字节数组所花费的时间 - 它大约 0.008秒。

以下是示例代码:

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopWatch = new Stopwatch();
        TimeSpan executionTime;

        StreamReader sr = new StreamReader("foo.txt");
        string sampleString = sr.ReadToEnd();
        sr.Close();

        ////1. Convert to bytes using Base64 Decoder (The real output!)
        //byte[] binaryData = Convert.FromBase64String(sampleString);

        //2. Convert to bytes using AsciiEncoding (Just for Fun!)
        byte[] binaryData = new System.Text.ASCIIEncoding().GetBytes(sampleString);
        Console.WriteLine("Byte Length: " + binaryData.Length);

        stopWatch.Start();
        FileStream fs = new FileStream("bar.txt", FileMode.Create, FileAccess.Write);
        fs.Write(binaryData, 0, binaryData.Length);
        fs.Flush();
        fs.Close();
        stopWatch.Stop();

        executionTime = stopWatch.Elapsed;
        Console.WriteLine("FileStream Write - Total Execution Time: " + executionTime.TotalSeconds.ToString());
        Console.Read();
    }
}

我对包含Base64编码字符串的大约5000个文件进行了测试,并且写入这两种字节数组所花费的时间差异几乎是10倍(使用 real编写字节数组的那个) 解码需要更多时间)。

使用Convert.FromBase64String获得的字节数组的长度小于使用ASCIIEncoding.GetBytes函数获得的字节数组的长度。

我想知道我要做的就是使用FileStream对象写一堆字节。那么为什么在将字节数组写入磁盘时会出现如此剧烈的性能差异(w.r.t. time)?

或者我做错了什么?请指教。

4 个答案:

答案 0 :(得分:1)

对于初学者来说,DateTime的分辨率很低(iirc为0.018秒)。所以最好使用秒表课程。

现在这并没有完全解释差异,但你可能会得到更好的数字。

答案 1 :(得分:1)

我给另一个问题提出了一些类似的建议,请查看 来自MS Research的{​​{3}}工具和参考资料。

他们会帮助您解决任何潜在的I / O问题,或者至少了解它们。

此外,您应该注意CLR these周围的问题。特别是在使用数组时(超过~80kb的任何东西都有次优的托管堆交互,请在同一过程中运行5000次)。

但是,真的,在再次看之后,我认为这些与你的引理没有密切关系。我在分析器中运行此代码,它只是显示转换。 Base64 正在消耗所有周期。

其他一些事情,在测试代码中,您应该总是连续运行2次以上的测试,抖动将有可能影响运行时负载。这可能导致执行时间的这种变化,这是惊人的。现在我认为你应该重新评估你的测试工具,试图考虑抖动和可能的大对象堆效应。 (将其中一个例程放在另一个例程之前......)。

答案 2 :(得分:1)

我认为您的代码中的主要问题是您正在尝试将卷心菜与胡萝卜(法语表达式)进行比较:

Convert.FromBase64String和ASCIIEncoding()。GetBytes根本不会做同样的事情。

只是尝试使用任何文本文件作为程序的输入,并且在使用ASCIIEncoding正常运行时,它将在FromBase64上失败。

现在有关性能影响的解释:

  • ASCIIEncoding()。GetBytes只是从你的文件中取一个字符并将其转换成一个字节(这是相当直接的:没有什么可做的)。例如,它会将'A'转换为0x41,将'Z'转换为0x5A ......

  • 对于Convert.FromBase64String,这是另一个故事。它实际上是将“base64编码的字符串”转换为字节数组。一个base64字符串是 - 比如说 - “二进制数据的可打印表示。更好的是,它是二进制数据的”文本“表示,允许它例如通过互联网线发送。邮件中的图像是base64编码的,因为邮件协议是基于文本的。因此,将back64转发到字节的过程根本不简单;因此性能受到影响。

Fyi,base64字符串看起来应该是这样的:

SABlAGwAbABvAHcAIABXAG8AcgBsAGQAIQA =

转换为“Hello World!”不是直接的,不是吗?

以下是有关base64格式的一些信息:http://en.wikipedia.org/wiki/Base64

希望这有帮助

答案 3 :(得分:0)

您可能想看看Jon Skeet最近在这个问题上写的一系列文章(以及随附的源项目)

herehere

具体来说,他正在比较缓冲与流媒体,但也有不同文件大小和线程数的有趣结果。