我试图使用python将 50亿行写入文件。我注意到随着文件越来越大,写入的性能越来越差。
例如,一开始我每秒写入1000万行,经过30亿行后,写入比以前慢10倍。
我想知道这是否与文件的大小有关?
也就是说,如果我将这个大文件分解为较小的文件或者文件的大小不会影响写入的性能,你认为性能会好转吗?
如果您认为它会影响性能,请解释原因吗?
- 更多信息 -
内存消耗始终相同(1.3%)。线的长度是相同的。所以逻辑是我从文件中读取一行(让我们称之为文件A)。文件A的每一行包含2个制表符分隔值,如果其中一个值具有某些特定的特征,我将相同的行添加到文件B.此操作是O(1),我只是将值转换为int并检查该值是否为%someNumber是我想要的7个标志中的任何一个。
每次从文件A读取10M行时,我输出行号。 (多数民众赞成我怎么知道性能下降)。文件B越来越大,对它的写入变慢。
操作系统是Ubuntu。
答案 0 :(得分:3)
使用这个Python脚本:
from __future__ import print_function
import time
import sys
import platform
if sys.version_info[0]==2:
range=xrange
times=[]
results=[]
t1=time.time()
t0=t1
tgt=5000000000
bucket=tgt/10
width=len('{:,} '.format(tgt))
with open('/tmp/disk_test.txt', 'w') as fout:
for line in range(1,tgt+1):
fout.write('Line {:{w},}\n'.format(line, w=width))
if line%bucket==0:
s='{:15,} {:10.4f} secs'.format(line, time.time()-t1)
results.append(s)
print(s)
t1=time.time()
else:
info=[platform.system(), platform.release(),sys.version, tgt, time.time()-t0]
s='\n\nDone!\n{} {}\n{} \n\n{:,} lines written in {:10.3f} secs'.format(*info)
fout.write('{}\n{}'.format(s, '\n'.join(results)))
print(s)
在Python 2和OS X下,打印:
500,000,000 475.9865 secs
1,000,000,000 484.6921 secs
1,500,000,000 463.2881 secs
2,000,000,000 460.7206 secs
2,500,000,000 456.8965 secs
3,000,000,000 455.3824 secs
3,500,000,000 453.9447 secs
4,000,000,000 454.0475 secs
4,500,000,000 454.1346 secs
5,000,000,000 454.9854 secs
Done!
Darwin 13.3.0
2.7.8 (default, Jul 2 2014, 10:14:46)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
5,000,000,000 lines written in 4614.091 secs
在Python 3.4和OS X下:
500,000,000 632.9973 secs
1,000,000,000 633.0552 secs
1,500,000,000 682.8792 secs
2,000,000,000 743.6858 secs
2,500,000,000 654.4257 secs
3,000,000,000 653.4609 secs
3,500,000,000 654.4969 secs
4,000,000,000 652.9719 secs
4,500,000,000 657.9033 secs
5,000,000,000 667.0891 secs
Done!
Darwin 13.3.0
3.4.1 (default, May 19 2014, 13:10:29)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
5,000,000,000 lines written in 6632.965 secs
生成的文件为139 GB。您可以看到在相对空的磁盘上(我的/tmp
路径是3 TB的容量),时间是线性的。
我的怀疑是,在Ubuntu下,你正在运行操作系统试图在EXT4磁盘上保持这个不断增长的文件连续。
回想一下,OS X的HFS +和Linux的EXT4文件系统都使用allocate-on-flush磁盘分配方案。 Linux操作系统还将尝试主动移动文件以允许分配连续(不分段)
对于Linux EXT4 - 您可以预先分配较大的文件以减少此影响。使用fallocate SO帖子中显示的this。然后在Python中回滚文件指针并在适当的位置覆盖。
您可以使用Python truncate方法创建文件,但结果取决于平台。
类似于(伪代码)的东西:
def preallocate_file(path, size):
''' Preallocate of file at "path" of "size" '''
# use truncate or fallocate on Linux
# Depending on your platform, You *may* be able to just the following
# works on BSD and OS X -- probably most *nix:
with open(path, 'w') as f:
f.truncate(size)
preallocate_file(fn, size)
with open(fn, 'r+') as f:
f.seek(0) # start at the beginning
# write whatever
f.truncate() # erases the unused portion...
答案 1 :(得分:2)
导致此问题的代码不是Python的一部分。如果要写入存在大文件问题的文件系统类型,则需要检查的代码是文件系统驱动程序。
对于变通方法,请为您的平台试验不同的文件系统(但这不再是编程问题,因此不属于StackOverflow)。
答案 2 :(得分:0)
正如你所说的那样,经过30亿行之后,你面临着性能崩溃,你的记忆总是一样(1.3%)!正如其他人提到的,Python I/O
代码中没有任何内容会影响基于filesize的性能。因此可能会因软件问题(OS)或硬件问题而发生!为了解决这个问题,我建议采用以下方式:
$ time python yourprogram.py
命令分析您的时间,向您显示以下结果:
real - refers to the actual elasped time
user - refers to the amount of cpu time spent outside of kernel
sys - refers to the amount of cpu time spent inside kernel specific functions
在THIS stachoverflow回答中详细了解real
,user
,sys
ConcernedOfTunbridgeWells。
$ pip install line_profiler
阅读文档HERE。你也可以安装memory_profiler查找你的线路使用了多少内存!使用此命令安装:
$ pip install -U memory_profiler
$ pip install psutil
和文档HERE
如果对象的引用被保留,即使对象不再使用,程序中也经常会发生内存泄漏。
找到这些“内存泄漏”的最快方法是使用Marius Gedminas编写的一个名为objgraph的强大工具。此工具允许您查看内存中的对象数量,还可以找到代码中包含对这些对象的引用的所有不同位置。
使用pipe for install objgraph:
pip install objgraph
安装此工具后,在代码中插入一个语句以调用调试器:
import pdb; pdb.set_trace()
哪些对象最常见?
在运行时,您可以通过运行以下方式检查程序中前20个最常见的对象: 像这样的结果:
(pdb) import objgraph
(pdb) objgraph.show_most_common_types()
MyBigFatObject 20000
tuple 16938
function 4310
dict 2790
wrapper_descriptor 1181
builtin_function_or_method 934
weakref 764
list 634
method_descriptor 507
getset_descriptor 451
type 439
所以请阅读文档HERE。
来源: http://mg.pov.lt/objgraph/#python-object-graphshttps://pypi.python.org/pypi/objgraph
http://www.appneta.com/blog/line-profiler-python/
https://sublime.wbond.net/packages/LineProfiler
http://www.huyng.com/posts/python-performance-analysis/
What do 'real', 'user' and 'sys' mean in the output of time(1)?