如何使用多个异步或缓冲 IO-Streams?

How to use multiple async or buffered IO-Streams?

我目前正在开发一个将大量数据 (~100mb) 写入 .txt 文件的程序。我在谷歌上搜索了一下如何优化不同的 IO 流,但并没有真正理解以下内容:

  1. 如何同时打开多个流
  2. 如果流被默认缓冲或者如果我必须使用 BufferedStream
  3. 异步流和缓冲流的区别是什么

这是我输出的当前状态:

for (int Row = 0; Row < RowCount; Row++)
{                   
    using (System.IO.StreamWriter file =
        new System.IO.StreamWriter(@"C:\Calculations\data1.txt", true))
            {
                file.WriteLine(Time + "\t" + Row + "\t" + Value1[Row]);
            }
    using (System.IO.StreamWriter file =
        new System.IO.StreamWriter(@"C:\Calculations\data2.txt", true))
            {
                file.WriteLine(Time + "\t" + tRow + "\t" + Value2[Row]);
            }
}

我认为这是做什么的:

如果我的看法是正确的,那么 100mb 的数据将需要大量的打开、关闭和刷新。我喜欢在开始时打开多个流,在计算时写入所有数据,然后关闭并刷新流。

你的问题有点多

一些不分先后的随机点

  1. 所有流在 .net 中都有一个内部缓冲区
  2. 不,您不必缓冲它们,但是您可以出于性能原因调整内部缓冲区的大小(这取决于很多因素)
  3. 异步IO是一个非常复杂的话题,从这里开始阅读Asynchronous File I/O

还有更多。

由于缓冲由流处理,您无需担心它,它会在需要时刷新它(根据默认值或您设置缓冲区的方式)。您无需关闭文件即可刷新。再一次,让流处理它,或者如果你愿意,你可以使用 'Flush'

自行刷新它

100mb 对于现代 SSD 驱动器来说不算多,它可以在几毫秒内完成。如果不需要,也无需打开和关闭它。然而,话虽如此,打开和关闭文件的开销很小,但它有时 beneficial/aesy 将访问包装在 using 语句中并在和平餐的基础上读写

最后,是的,您可以打开多个流,但它们不是线程安全的。这意味着,由于它们只有 1 个内部缓冲区,您将不得不使用锁,或者打开和关闭文件以确保其完整性。这并不是说多个线程不能写入一个文件,它只是说它并不像它应该的那样微不足道。

如果您想保持文件打开以同步读写,请不要忘记在完成后 close/dispose 它们

祝你好运

经过更多研究,我找到了第一个问题的解决方案。您可以像这样打开多个 IO-Streams:

StreamWriter file1 = File.CreateText(@"C:\Outputtests\OutputTest1.txt");
StreamWriter file2 = File.CreateText(@"C:\Outputtests\OutputTest2.txt");

像这样你需要自己刷新和关闭流。

我比较了 运行 次,它为我的硬盘节省了大约 10000 倍:

static void Main(string[] args)
{
    Stopwatch sw1 = new Stopwatch();
    Stopwatch sw2 = new Stopwatch();
    Stopwatch sw3 = new Stopwatch();

    sw1.Start();                            //first version: opens and closes file each time -> takes around 1 minute total
    for (int i = 0; i < 10000; i++)
    {
        using (System.IO.StreamWriter file1 =
            new System.IO.StreamWriter(@"C:\Outputtests\OutputTest1.txt", true))
        {
            file1.WriteLine(i);
        }
    }
    sw1.Stop();

    sw2.Start();                            //second version: flushes each time -> takes around 50ms
    StreamWriter file2 = File.CreateText(@"C:\Outputtests\OutputTest2.txt");
    for (int i = 0; i < 10000; i++)
    {
        file2.WriteLine(i);
        file2.Flush();
    }
    file2.Close();
    sw2.Stop();

    sw3.Start();                            //third version: flushes at the end -> takes around 10ms
    StreamWriter file3 = File.CreateText(@"C:\Outputtests\OutputTest3.txt");
    for (int i = 0; i < 10000; i++)
    {
        file3.WriteLine(i);
    }
    file3.Flush();
    file3.Close();
    sw3.Stop();

    Console.WriteLine("Output 1:\t" + sw1.ElapsedMilliseconds.ToString() + Environment.NewLine + "Output 2:\t" + sw2.ElapsedMilliseconds.ToString() + Environment.NewLine + "Output 3:\t" + sw3.ElapsedMilliseconds.ToString());
    Console.ReadKey();
}

不确定在必须刷新之前应该在 IO-Stream 中存储多少。