代码之家  ›  专栏  ›  技术社区  ›  wich

python字符串格式太慢

  •  8
  • wich  · 技术社区  · 15 年前

    我使用下面的代码来记录一个映射,当它只包含0时速度很快,但是一旦映射中有实际的数据,它就会变得非常慢…有什么办法可以更快地完成这个任务吗?

    log_file = open('testfile', 'w')
    for i, x in ((i, start + i * interval) for i in range(length)):
        log_file.write('%-5d %8.3f %13g %13g %13g %13g %13g %13g\n' % (i, x,
            map[0][i], map[1][i], map[2][i], map[3][i], map[4][i], map[5][i]))
    
    3 回复  |  直到 15 年前
        1
  •  3
  •   Mike Graham    15 年前

    我建议您使用 cProfile 模块和后处理结果,如 http://docs.python.org/library/profile.html . 这将让您确切地知道 str.__mod__ 对于字符串格式,以及执行其他操作(如编写文件和执行 __getitem__ 查找 map[0][i] 诸如此类。

        2
  •  2
  •   Warren P    15 年前

    首先我核对了%的反向报价。%更快。然后我对照'string'。format()检查了%(元组)。最初的一个错误让我觉得它更快。但是没有。速度更快。

    因此,您已经在以python中最快的方式进行大量的浮点到字符串转换。

    下面的演示代码是丑陋的演示代码。请不要跟我讲xrange和range或者其他迂腐的东西。谢谢。

    我的特别和高度不科学的测试表明,对于下面的测试代码,在Linux上对Python2.5的(a)%(1.234,)操作比在Linux上对Python2.6的(1.234,…)操作快,但前提是尝试使用“string.format()在2.6之前的Python版本上不起作用。等等。

    # this code should never be used in production.
    # should work on linux and windows now.
    
    import random
    import timeit
    import os
    import tempfile
    
    
    start = 0
    interval = 0.1
    
    amap = [] # list of lists
    tmap = [] # list of tuples
    
    def r():
        return random.random()*500
    
    for i in xrange(0,10000):
            amap.append ( [r(),r(),r(),r(),r(),r()] )
    
    for i in xrange(0,10000):
            tmap.append ( (r(),r(),r(),r(),r(),r()) )
    
    
    
    
    def testme_percent():
        log_file = tempfile.TemporaryFile()
        try:
            for qmap in amap:
                s = '%g %g %g %g %g %g \n' % (qmap[0], qmap[1], qmap[2], qmap[3], qmap[4], qmap[5]) 
                log_file.write( s)
        finally:
            log_file.close();
    
    def testme_tuple_percent():
        log_file = tempfile.TemporaryFile()
        try:    
            for qtup in tmap:
                s = '%g %g %g %g %g %g \n' % qtup
                log_file.write( s );
        finally:
            log_file.close();
    
    def testme_backquotes_rule_yeah_baby():
        log_file = tempfile.TemporaryFile()
        try:
            for qmap in amap:
                s = `qmap`+'\n'
                log_file.write( s );
        finally:
            log_file.close();        
    
    def testme_the_new_way_to_format():
        log_file = tempfile.TemporaryFile()
        try:
            for qmap in amap:
                s = '{0} {1} {2} {3} {4} {5} \n'.format(qmap[0], qmap[1], qmap[2], qmap[3], qmap[4], qmap[5]) 
                log_file.write( s );
        finally:
            log_file.close();
    
    # python 2.5 helper
    default_number = 50 
    def _xtimeit(stmt="pass",  timer=timeit.default_timer,
               number=default_number):
        """quick and dirty"""
        if stmt<>"pass":
            stmtcall = stmt+"()"
            ssetup = "from __main__ import "+stmt
        else:
            stmtcall = stmt
            ssetup = "pass"
        t = timeit.Timer(stmtcall,setup=ssetup)
        try:
          return t.timeit(number)
        except:
          t.print_exc()
    
    
    # no formatting operation in testme2
    
    print "now timing variations on a theme"
    
    #times = []
    #for i in range(0,10):
    
    n0 = _xtimeit( "pass",number=50)
    print "pass = ",n0
    
    n1 = _xtimeit( "testme_percent",number=50);
    print "old style % formatting=",n1
    
    n2 = _xtimeit( "testme_tuple_percent",number=50);
    print "old style % formatting with tuples=",n2
    
    n3 = _xtimeit( "testme_backquotes_rule_yeah_baby",number=50);
    print "backquotes=",n3
    
    n4 = _xtimeit( "testme_the_new_way_to_format",number=50);
    print "new str.format conversion=",n4
    
    
    #        times.append( n);
    
    
    
    
    print "done"    
    

    我认为可以通过在其他地方构建浮动元组来优化代码,无论您在何处构建该映射,首先,构建元组列表,然后以这种方式应用fmt_string%元组:

    for tup in mytups:
        log_file.write( fmt_str % tup )
    

    我可以把8.7秒缩短到8.5秒,方法是把making-a-tuple部分从for循环中去掉。也不多。大男孩那里有浮点格式,我相信这总是要昂贵的。

    替代方案:

    你有没有考虑过不写文本这样大的日志,而是用可用的最快的“持久性”方法保存它们,然后在需要时编写一个简短的实用程序将它们转储到文本中?有些人将numpy与非常大的数字数据集一起使用,而且似乎他们不会使用逐行转储来存储他们的数据。见:

    http://thsant.blogspot.com/2007/11/saving-numpy-arrays-which-is-fastest.html

        3
  •  0
  •   hughdbrown    15 年前

    如果不想深入到优化这个代码的泥沼中,我会把代码写得更像这样:

    log_file = open('testfile', 'w')
    x = start
    map_iter = zip(range(length), map[0], map[1], map[2], map[3], map[4], map[5])
    fmt = '%-5d %8.3f %13g %13g %13g %13g %13g %13g\n'
    for i, m0, m1, m2, m3, m4, m5 in mapiter:
        s = fmt % (i, x, m0, m1, m2, m3, m4, m5)
        log_file.write(s)
        x += interval
    

    但是我会考虑一下建议,不要用python内置名来命名变量,比如 map .