4

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

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

我测量了写入字节数组的时间——结果大约是0.116 秒。

只是为了好玩,我使用 ASCIIEncoding.GetBytes 函数从同一个 Base64 编码字符串中获取了字节数组(尽管我知道这不会给出正确的解码输出 - 我只是想尝试一下)。我使用 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();
    }
}

我对大约 5000 个包含 Base64 编码字符串的文件进行了测试,写入这两种类型的字节数组所需的时间差几乎是 10 倍(使用 真实解码写入字节数组的时间更长)。

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

我想知道我要做的就是使用 FileStream 对象写入一堆字节。那么,为什么在将字节数组写入磁盘时会有如此巨大的性能差异(所需时间)?

还是我做错了什么?请指教。

4

4 回答 4

1

对于初学者, DateTime 的分辨率较低(iirc 0.018 s)。所以最好使用秒表类。

现在这并不能完全解释差异,但您可能会得到一些更好的数字。

于 2009-05-15T07:59:54.307 回答
1

我对另一个问题给出了一些类似的建议,请查看 MS Research 的这些工具和参考资料。

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

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

但是,真的,再看一遍后,我认为这些与您的引理没有那么密切的关系。我在分析器中运行了这段代码,它只是显示了 Convert. Base64正在消耗您的所有周期。

其他一些事情,在您的测试代码中,您应该始终连续运行测试 2 次以上,抖动将有机会影响运行时负载。这可能会导致执行时间发生如此大的变化,这太神奇了。现在我认为你应该重新评估你的测试工具,尝试考虑抖动和可能的大对象堆效应。(将这些例程之一放在另一个前面......)。

于 2009-05-15T08:00:48.470 回答
1

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

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

只需尝试使用任何文本文件作为程序的输入,它会在 FromBase64 上失败,而使用 ASCIIEncoding 运行良好。

现在解释一下性能命中:

  • ASCIIEncoding().GetBytes 只是从文件中取出一个字符并将其转换为一个字节(这很简单:没有什么可做的)。例如,它会将“A”翻译成 0x41,将“Z”翻译成 0x5A……

  • 对于 Convert.FromBase64String,这是另一回事。它实际上是将“base64 编码字符串”转换为字节数组。base64 字符串是 - 比方说 - 二进制数据的“可打印表示”。更好的是,它是二进制数据的“文本”表示,例如,可以通过 Internet 线路发送。邮件中的图像是 base64 编码的,因为邮件协议是基于文本的。因此将 base64 来回转换为字节的过程一点也不简单;因此会影响性能。

仅供参考,base64 字符串应如下所示:

SABlAGwAbABvAHcAIABXAG8AcgBsAGQAIQA=

翻译为“你好世界!” 不是即时的,不是吗?

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

希望这可以帮助

于 2009-05-15T08:19:28.270 回答
0

您可能想查看 Jon Skeet 最近就该问题撰写的一系列文章(以及随附的源项目)

这里这里

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

于 2009-05-15T08:12:45.417 回答