【问题标题】:write file need to optimised for heavy traffic写入文件需要针对大流量进行优化
【发布时间】:2012-05-31 06:17:10
【问题描述】:

我对C#很陌生,这是我的第一个问题,请对我温柔

我正在尝试编写一个应用程序来从数据提供者那里捕获一些刻度数据,下面是程序的主要部分

void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
{

    output myoutput = new output();

    myoutput.time = e.TimeStamp;
    myoutput.product = e.Product.ToString();
    myoutput.type = Enum.GetName(typeof(ZenFire.TickType), e.Type);
    myoutput.price = e.Price;
    myoutput.volume = e.Volume;

    using (StreamWriter writer = File.AppendText("c:\\log222.txt"))
    {

        writer.Write(myoutput.time.ToString(timeFmt) + ",");
        writer.Write(myoutput.product + "," );
        writer.Write(myoutput.type + "," );
        writer.Write(myoutput.price + ",");
        writer.Write(myoutput.volume + ",");

    }

我已经成功地将数据写入文本文件,但是我知道这个方法在高峰时间每秒会被调用 10000 次,并且打开一个文件并每秒附加很多次是非常低效的,我被指出使用缓冲区或某种方式,但我不知道该怎么做,我尝试阅读文档但我仍然不明白,这就是我在这里求助的原因。

请给我一些(工作的)sn-p 代码,以便我可以指出写入方向。谢谢

编辑:我已经尽可能地简化了代码

    using (StreamWriter streamWriter = File.AppendText("c:\\output.txt"))
    {
        streamWriter.WriteLine(string.Format("{0},{1},{2},{3},{4}",
                        e.TimeStamp.ToString(timeFmt),
                        e.Product.ToString(),
                        Enum.GetName(typeof(ZenFire.TickType), e.Type),
                        e.Price,
                        e.Volume));
    }

ED 告诉我将我的流制作成一个字段,语法是什么样的?任何人都可以发布一些代码来帮助我吗?非常感谢

【问题讨论】:

  • 一种可能的替代方法是将写入操作推送到队列中,并在可能的情况下触发最终写入队列内容的后台线程
  • 我已经展示了如何创建一个字段 (private StreamWriter _writer;)
  • @andrey,谢谢,请在此处阅读我的问题的第 2 部分 stackoverflow.com/questions/10884106/…

标签: c# io


【解决方案1】:

您需要为流创建一个字段而不是局部变量。在构造函数中初始化一次,不要忘记在某个地方关闭它。最好实现IDisposable接口并在Dispose()方法中关闭流。

IDisposable

class MyClass : IDisposable {
    private StreamWriter _writer;

    MyClass() {
        _writer = File.App.....;
    }

    void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
    {

        output myoutput = new output();

        myoutput.time = e.TimeStamp;
        myoutput.product = e.Product.ToString();
        myoutput.type = Enum.GetName(typeof(ZenFire.TickType), e.Type);
        myoutput.price = e.Price;
        myoutput.volume = e.Volume;


        _writer.Write(myoutput.time.ToString(timeFmt) + ",");
        _writer.Write(myoutput.product + "," );
        _writer.Write(myoutput.type + "," );
        _writer.Write(myoutput.price + ",");
        _writer.Write(myoutput.volume + ",");

    }

    public void Dispose() { /*see the documentation*/ }
}

【讨论】:

  • 感谢您的输入,但我想强调的是,此方法将在高峰时段每秒调用约 10000 次。我知道我需要实现某种缓冲区,但我不知道如何实现它。有人可以帮我怎么做(用一些简单的代码)?
  • 从未尝试过,但您可以在文件流上使用BufferedStream,并在此缓冲流上创建 StreamWriter。
【解决方案2】:

你可以做很多事情

第 1 步。确保不要进行多次 io 调用和字符串连接。

Output myOutput = new Outoput(e); // Maybe consruct from event args?

// Single write call, single string.format
writer.Write(string.Format("{0},{1},{2},{3},{4},{5}", 
  myOutput.Time.ToString(), 
  myOutput.Product, 
  ...);

无论您当前的表现如何,我都建议您这样做。我还做了一些外观上的更改(变量/属性/类名大小写。您应该查看变量和属性之间的区别及其推荐的大小写等)

第 2 步。分析您的表现,看看它是否符合您的要求。如果是这样,则无需再做任何事情。如果性能还是太差,可以

  • 保持文件打开并在处理程序关闭时将其关闭。
  • 写入缓冲区并定期刷新。
  • 使用像 log4net 这样的记录器框架,它会在内部为您处理上述问题,并处理多线程访问日志文件等棘手问题。

【讨论】:

    【解决方案3】:

    我会使用 String.Format:

    using (StreamWriter writer = new StreamWriter(@"c:\log222.txt", true))
            {
                writer.AutoFlush = true;
                writer.Write(String.Format("{0},{1},{2},{3},{4},", myoutput.time.ToString(timeFmt), 
                    myoutput.product, myoutput.type, myoutput.price, myoutput.volume);
            }
    

    如果在字符串之前使用@,则不必使用双精度\

    这要快得多 - 您只需向文件写入一次,而不是 5 次。此外,您不要将 + 运算符与字符串一起使用,这不是最快的操作;)

    另外——如果这是多线程应用程序——你应该考虑使用一些锁。它会阻止应用程序尝试从例如写入文件。一次 2 个线程。

    【讨论】:

    • -1 StreamWriter 上的 AutoFlush 默认为 falseso the writes are buffered。这就是为什么我们不对性能做出假设的原因。测试或(至少)阅读文档。
    • @EdS。 - 是的,忘记写那行了。已更正-谢谢。顺便说一句-不要对已进行的测试进行假设-我经常使用这种方式每次都写下几百万行。它运行得非常快。
    • 它不能解决问题。 OP 已经说过这个函数每秒会运行很多次。您建议将 N 次对 Write() 的调用合并为一个将提高性能,因为这将减少刷新缓冲区和将数据写入磁盘的次数。这是错误的,原因有两个。第一个我已经提到过。 真正的 问题是文件在每次调用函数时都会打开、写入、刷新到磁盘并关闭。 是真正的问题,您的回答并没有解决它。一个好的第一次尝试是停止创建一个新的流
    • ...每次调用函数时。
    • 在阅读了我的第一条评论之后……这听起来比我预想的更加说教和傲慢。对不起。
    猜你喜欢
    • 2012-07-16
    • 2012-07-17
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多