Python中,使用cStringIO比使用StringIO在写入时需要更多的时间(字符串方法的性能)。

8

我正在研究Python中的字符串方法,以便使用最快的方法。 我有这段代码来测试文件中的字符串拼接、StringIO、BytesIO和正常字符串。

#!/usr/bin/env python
#title           : pythonTiming.py
#description     : Will be used to test timing function in python
#author          : myusuf
#date            : 19-11-2014
#version         : 0
#usage           :python pythonTiming.py
#notes           :
#python_version  :2.6.6  
#==============================================================================

import time
import cStringIO
import StringIO

class Timer(object):

    def __enter__(self):
        self.start = time.time()
        return self

    def __exit__(self, *args):
        self.end = time.time()
        self.interval = self.end - self.start

testbuf = """ Hello This is a General String that will be repreated
This string will be written to a file , StringIO and a sregualr strin then see the best to handle string according to time 

""" * 1000

MyFile = open("./testfile.txt" ,"wb+")
MyStr  = ''
MyStrIo = StringIO.StringIO()
MycStrIo = cStringIO.StringIO()

def strWithFiles():
    global MyFile
    print "writing string to file "
    for index in range(1000):
        MyFile.write(testbuf) 
    pass

def strWithStringIO():
    global MyStrIo
    print "writing string to StrinIO "
    for index in range(1000):
        MyStrIo.write(testbuf)

def strWithStr():
    global MyStr
    print "Writing String to STR "
    for index in range(500):
        MyStr =  MyStr +  testbuf

def strWithCstr():
    global MycStrIo
    print "writing String to Cstring"
    for index in range(1000):
        MycStrIo.write(testbuf)

with Timer() as t:
    strWithFiles()
print('##Request took %.03f sec.' % t.interval)

with Timer() as t:                                                                                
    strWithStringIO()
print('###Request took %.03f sec.' % t.interval)  

with Timer() as t:                                                                                
    strWithCstr()
print('####Request took %.03f sec.' % t.interval)  

with Timer() as t:
    read1 = 'x' + MyFile.read(-1)
print('file read ##Request took %.03f sec.' % t.interval)

with Timer() as t:
    read2 = 'x' + MyStrIo.read(-1)
print('stringIo read ###Request took %.03f sec.' % t.interval)

with Timer() as t:
    read3 = 'x' + MycStrIo.read(-1)
print('CString read ####Request took %.03f sec.' % t.interval)




MyFile.close()
  1. Python文档网站称cStringIOStringIO更快,但实际测试结果表明在字符串连接方面StringIO表现更好。为什么?

  2. 另一方面,从cStringIO中读取数据比从StringIO中读取数据要快(与文件类似),因为我看到文件和cStringIO的实现都是用C语言编写的,那么为什么字符串连接速度较慢呢?

  3. 除了这些方法之外,还有没有其他更快的处理字符串的方式?


1
Python中的字符串连接在CPython解释器中执行的代码高度优化,但这并不一定适用于手动编写的cStringIO模块中的C代码。请参见PEP-8的Programming Recommendations部分中的第一个要点。 - martineau
感谢提供的链接,它非常有帮助。 在我的性能分析程序中,与StringIO相比,对字符串进行操作的成本要高得多,但我很好奇为什么在连接字符串时cStringIO需要比StringIO花费更多的时间,尽管cStringIO是用C编写的。 - Muhammad Yusuf
1个回答

13
StringIO之所以表现更好,是因为它在幕后只保留了一个列表,列出了所有已写入它的字符串,并且仅在必要时将它们组合起来。因此,写操作就像将对象附加到列表一样简单。但是,cStringIO模块没有这个优势,必须复制每个字符串的数据到其缓冲区中,并根据需要调整其缓冲区的大小(当写入大量数据时会创建许多冗余的数据复制)。
由于您正在编写大量较大的字符串,因此与cStringIO相比,在StringIO中的工作量较少。当从您已经写入的StringIO对象中读取时,它可以通过计算已写入它的字符串长度之和并预分配该大小的缓冲区来优化所需的复制量。
然而,StringIO不是连接一系列字符串的最快方法。这是因为它提供了额外的功能(在缓冲区的不同部分寻找并在那里写入数据)。如果不需要此功能,而只是想将一系列字符串连接起来,则str.join是最快的方法。
joined_string = "".join(testbuf for index in range(1000))
# or building the list of strings to join separately
strings = []
for i in range(1000):
    strings.append(testbuf)
joined_string = "".join(strings)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接