性能 - Python与C#/ C ++ / C读取char-by-char

时间:2009-08-26 17:14:00

标签: c# python performance character

所以我有这些巨大的XML文件(和巨人,我的意思是1.5GB +),他们没有CRLF。我正在尝试运行类似diff的程序来查找这些文件之间的差异。

由于我还没有找到一个不会因内存耗尽而爆炸的差异程序,我决定最好的办法是在关闭标签后添加CRLF。

我编写了一个python脚本来读取char-by-char并在'>'之后添加新行。问题是我在大约1995年的单核PC上运行这个或者说是荒谬的,当我同时进行两次转换时,它只处理大约20MB /小时。

任何想法,如果用C#/ C / C ++写这个会产生任何好处吗?如果没有,有没有人知道将逐字节的diff程序?感谢。


修改

这是我处理函数的代码......

def read_and_format(inputfile, outputfile):
    ''' Open input and output files, then read char-by-char and add new lines after ">" '''
    infile = codecs.open(inputfile,"r","utf-8")
    outfile = codecs.open(outputfile,"w","utf-8")

    char = infile.read(1) 
    while(1):
        if char == "":
            break
        else:
            outfile.write(char)
            if(char == ">"):
                outfile.write("\n")
        char = infile.read(1)

    infile.close()
    outfile.close()

EDIT2: 谢谢你们的精彩回应。增加读取大小创造了令人难以置信的速度提升。问题解决了。

8 个答案:

答案 0 :(得分:11)

一次读取和写入一个字符几乎总是很慢,因为磁盘是基于块的设备,而不是基于字符的设备 - 它将读取的内容远远超过您之后的一个字节,剩余部分需要丢弃。

尝试一次读取和写入更多,比如8192字节(8KB),然后在写出之前在该字符串中查找并添加换行符 - 您应该节省大量的性能,因为需要的I / O要少得多。

正如LBushkin指出的那样,你的I / O库可能正在进行缓冲,但除非有某种形式的文档证明这确实发生了(对于读写),在重写之前尝试它是一件相当容易的事情。不同的语言。

答案 1 :(得分:3)

你为什么不用sed? cat giant.xml | sed's /> /> \ x0a \ x0d / g'>巨与-linebreaks.xml

答案 2 :(得分:1)

不是逐字节读取,而是每次读取字节都会产生磁盘访问权限,请尝试一次读取大约20 MB并执行搜索+替换:)

您可以在记事本中执行此操作....

Billy3

答案 3 :(得分:1)

对于您描述的问题类型,我怀疑您用于比较数据的算法将比I / O模型或语言具有更显着的效果。事实上,字符串分配和搜索在这里可能比其他任何东西都要贵。

在您自己撰写之前的一些一般性建议:

  1. 如果有可用的计算机,请尝试在更快的计算机上运行。这将产生巨大的差异。
  2. 在线查找现有的XML差异工具......不要自己写一个。
  3. 如果要用C#(或Java或C / C ++)编写,我会执行以下操作:

    1. 将一个相当大的块一次性读入内存(假设介于200k和1M之间)
    2. 分配一个两倍大小的空块(假设每个角色的最坏情况是'>')
    3. 从输入块复制到输出块,在每个'>'之后有条件地附加CRLF字符。
    4. 将新块写入磁盘。
    5. 重复,直到处理完所有数据。
    6. 此外,您还可以编写这样的程序以在多个线程上运行,这样一旦线程在内存中执行CRLF插入,就会从磁盘中读取一个单独的线程块。这种类型的并行化很复杂......所以如果你真的需要最大的性能,我只会这样做。

      如果您需要,这是一个非常简单的C#程序,可以帮助您入门。它接受命令行上的输入文件路径和输出路径,并执行您要查找的替换('>'==> CRLF)。这个样本有待改进(并行处理,流式传输,一些验证等)......但它应该是一个不错的开始。

      using System;
      using System.IO;
      
      namespace ExpandBrackets
      {
          class Program
          {
              static void Main(string[] args)
              {
                  if (args.Length == 2)
                  {
                      using( StreamReader input = new StreamReader( args[0] ) )
                      using( StreamWriter output = new StreamWriter( args[1] ) )
                      {
                          int readSize = 0;
                          int blockSize = 100000;
                          char[] inBuffer = new char[blockSize];
                          char[] outBuffer = new char[blockSize*3];
                          while( ( readSize = input.ReadBlock( inBuffer, 0, blockSize ) ) > 0 )
                          {
                              int writeSize = TransformBlock( inBuffer, outBuffer, readSize );
                              output.Write( outBuffer, 0, writeSize );
                          }
                      }
                  }
                  else
                  {
                      Console.WriteLine( "Usage:  repchar {inputfile} {outputfile}" );
                  }
              }
      
              private static int TransformBlock( char[] inBuffer, char[] outBuffer, int size )
              {
                  int j = 0;
                  for( int i = 0; i < size; i++ )
                  {
                      outBuffer[j++] = inBuffer[i];
                      if (inBuffer[i] == '>') // append CR LF
                      {
                          outBuffer[j++] = '\r';
                          outBuffer[j++] = '\n';
                      }
                  }
                  return j;
              }
          }
      }
      

答案 4 :(得分:0)

在某些时候,通常提到的所有语言都会恢复到C运行时库,以便逐字节文件访问。用C语言写这个可能是最快的选择。

然而,我怀疑它会提供巨大的速度提升。如果你正确地做事,Python的速度相当快。

真正提高速度的主要方法是引入线程。如果您在一个线程中的大块中读取文件中的数据,并且有一个单独的线程执行了换行处理+差异处理,则可以显着提高此算法的速度。这在C ++,C#或IronPython中可能比直接在C或CPython中更容易实现,因为它们提供了非常简单的高级同步工具来处理线程问题(特别是在使用.NET时)。

答案 5 :(得分:0)

您可以尝试xmldiff - http://msdn.microsoft.com/en-us/library/aa302294.aspx

我没有将它用于如此庞大的数据,但我认为它会得到合理的优化

答案 6 :(得分:0)

我把它作为对另一个答案的评论,但如果你错过了 - 你可能想看看The Shootout。它是针对多种语言的各种问题的高度优化的代码集。

根据这些结果,Python往往比c慢约50倍(但它比其他解释语言快)。相比之下,Java比c慢约2倍。如果你去了一种编译速度较快的语言,我不明白为什么你不会看到类似的增长。

顺便说一句,从枪战中获得的数字是非常难以攻击的,你不能真正挑战他们,相反,如果你不相信这些数字是公平的,因为用你最喜欢的语言解决问题的代码不是没有正确优化,那么你可以自己提交更好的代码。许多人这样做的行为意味着那里的大部分代码都非常适合每种流行语言。如果您向他们展示更优化的编译器或解释器,他们也可以包含它的结果。

哦:除了C#之外,这只是由MONO代表的,所以如果微软的编译器更加优化,它就不会显示出来。所有测试似乎都在Linux机器上运行。我的猜测是微软的C#应该以与Java相同的速度运行,但是枪战列出的单声道速度有点慢(大约是C的3倍)。

答案 7 :(得分:0)

正如其他人所说,如果你用C语言做,那将是无与伦比的,因为C缓冲I / O和getc()是内联的(在我的记忆中)。

您的真实性能问题将出现在差异中。

也许那里有一个非常好的,但对于那些大小的文件,我怀疑它。为了好玩,我是一个自己动手的人。我将使用的策略是在每个文件中有一个滚动窗口,长度为几兆字节。不匹配的搜索策略是对角线搜索,如果您在第i行和第j行,则按以下顺序进行比较:

line(i+0) == line(j+0)

line(i+0) == line(j+1)
line(i+1) == line(j+0)

line(i+0) == line(j+2)
line(i+1) == line(j+1)
line(i+2) == line(j+0)

等等。毫无疑问,有一种更好的方法,但如果我要自己编写代码并管理滚动窗口,那就是我要尝试的。