列表在python中表现不佳?

Joh*_*ohn 3 python

我试图从一些巨大的文件中读取数据并将其写回来,但我意识到主要成本来自于将数据分配到列表而不是从文件中读取或写入数据....

    rows = [None] * 1446311
    begin = datetime.datetime.now()
    for i in range( 1446311 ):
       row = csvReader.next()
       rows[i] = row
    print datetime.datetime.now() - begin
Run Code Online (Sandbox Code Playgroud)

上面的代码需要18秒但是5秒,如果我注释掉第5行(rows[i] = row),我已经预先建立了列表(即保留了内存),但为什么它仍然如此慢?我能做什么让它更快?我尝试row for row in csvReader但是表现更差......

约翰

Gar*_*ees 6

我得到了类似的结果,但不像你的那么戏剧化.(注意使用timeit模块来执行时间代码,并注意我已经将列表创建考虑在内,因为它对两个测试用例都是通用的.)

import csv
from timeit import Timer

def write_csv(f, n):
    """Write n records to the file named f."""
    w = csv.writer(open(f, 'wb'))
    for i in xrange(n):?
        w.writerow((i, "squared", "equals", i**2))

def test1(rows, f, n):
    for i, r in enumerate(csv.reader(open(f))):
        rows[i] = r

def test2(rows, f, n):
    for i, r in enumerate(csv.reader(open(f))):
        pass

def test(t): 
    return (Timer('test%d(rows, F, N)' % t,
                  'from __main__ import test%d, F, N; rows = [None] * N' % t)
            .timeit(number=1))

>>> N = 1446311
>>> F = "test.csv"
>>> write_csv(F, N)
>>> test(1)
2.2321770191192627
>>> test(2)
1.7048690319061279
Run Code Online (Sandbox Code Playgroud)

这是我对正在发生的事情的猜测.在两个测试中,CSV读取器从文件中读取记录,并在内存中创建表示该记录的数据结构.

test2没有存储记录的情况下,数据结构或多或少立即被删除(在循环的下一次迭代中,row变量被更新,因此前一记录的引用计数减少,因此内存被回收) .这使得用于前一个记录的内存可以重用:这个内存已经存在于计算机的虚拟内存表中,并且可能仍然在缓存中,因此它(相对)快.

test1存储记录的情况下,每个记录必须在新的内存区域中分配,该区域必须由操作系统分配,并复制到缓存中,因此它(相对)慢.

所以时间不是由列表赋值占用,而是由内存分配占用.


这是另外几个测试,说明正在发生的事情,没有csv模块的复杂因素.在test3我们为每一行创建一个新的100元素列表,并存储它.在test4我们为每一行创建一个新的100元素列表,但我们不存储它,我们将它丢弃,以便下次循环时可以重用内存.

def test3(rows, f, n):
    for i in xrange(n):
        rows[i] = [i] * 100

def test4(rows, f, n):
    for i in xrange(n):
        temp = [i] * 100
        rows[i] = None

>>> test(3)
9.2103338241577148
>>> test(4)
1.5666921138763428
Run Code Online (Sandbox Code Playgroud)

所以我认为,如果您不需要同时将所有行存储在内存中,请不要这样做!如果可以的话,一次一个地读取它们,一次处理一个,然后忘记它们,以便Python可以解除它们.