在python中编写巨大的字符串

时间:2015-02-09 22:20:22

标签: python performance python-3.x file-io

我有一个很长的字符串,差不多一兆字节,我需要写一个文本文件。常规

file = open("file.txt","w")
file.write(string)
file.close()

有效,但速度太慢,有没有办法让我写得更快?

我正在尝试将数百万位数字写入文本文件 该数字大约为math.factorial(67867957)

这是分析中显示的内容:

    203 function calls (198 primitive calls) in 0.001 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 re.py:217(compile)
        1    0.000    0.000    0.000    0.000 re.py:273(_compile)
        1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
        1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
        4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
      3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)
        1    0.000    0.000    0.000    0.000 sre_compile.py:341(_compile_info)
        2    0.000    0.000    0.000    0.000 sre_compile.py:442(isstring)
        1    0.000    0.000    0.000    0.000 sre_compile.py:445(_code)
        1    0.000    0.000    0.000    0.000 sre_compile.py:460(compile)
        5    0.000    0.000    0.000    0.000 sre_parse.py:126(__len__)
       12    0.000    0.000    0.000    0.000 sre_parse.py:130(__getitem__)
        7    0.000    0.000    0.000    0.000 sre_parse.py:138(append)
      3/1    0.000    0.000    0.000    0.000 sre_parse.py:140(getwidth)
        1    0.000    0.000    0.000    0.000 sre_parse.py:178(__init__)
       10    0.000    0.000    0.000    0.000 sre_parse.py:183(__next)
        2    0.000    0.000    0.000    0.000 sre_parse.py:202(match)
        8    0.000    0.000    0.000    0.000 sre_parse.py:208(get)
        1    0.000    0.000    0.000    0.000 sre_parse.py:351(_parse_sub)
        2    0.000    0.000    0.000    0.000 sre_parse.py:429(_parse)
        1    0.000    0.000    0.000    0.000 sre_parse.py:67(__init__)
        1    0.000    0.000    0.000    0.000 sre_parse.py:726(fix_flags)
        1    0.000    0.000    0.000    0.000 sre_parse.py:738(parse)
        3    0.000    0.000    0.000    0.000 sre_parse.py:90(__init__)
        1    0.000    0.000    0.000    0.000 {built-in method compile}
        1    0.001    0.001    0.001    0.001 {built-in method exec}
       17    0.000    0.000    0.000    0.000 {built-in method isinstance}
    39/38    0.000    0.000    0.000    0.000 {built-in method len}
        2    0.000    0.000    0.000    0.000 {built-in method max}
        8    0.000    0.000    0.000    0.000 {built-in method min}
        6    0.000    0.000    0.000    0.000 {built-in method ord}
       48    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        5    0.000    0.000    0.000    0.000 {method 'find' of 'bytearray' objects}
        1    0.000    0.000    0.000    0.000 {method 'items' of 'dict' objects}

2 个答案:

答案 0 :(得分:2)

您的问题是str(long)对于Python中的大型intergers(数百万位)来说非常慢。 It is a quadratic operation (in number of digits) in Python,即对于~1e8位数,可能需要~1e16次操作才能将整数转换为十进制字符串。

写入文件500MB不应该花费数小时,例如:

$ python3 -c 'open("file", "w").write("a"*500*1000000)'

几乎立即返回。 ls -l file确认文件已创建且具有预期大小。

计算math.factorial(67867957)(结果有~500M位)可能需要几个小时但是使用pickle保存它是瞬间的:

import math
import pickle

n = math.factorial(67867957) # takes a long time
with open("file.pickle", "wb") as file:
    pickle.dump(n, file) # very fast (comparatively)

使用n = pickle.load(open('file.pickle', 'rb'))加载它只需不到一秒钟。

我的机器上

str(n)仍在运行(50小时后)。

要快速获得十进制表示,您可以use gmpy2

$ python -c'import gmpy2;open("file.gmpy2", "w").write(str(gmpy2.fac(67867957)))'

我的机器上只需不到10分钟。

答案 1 :(得分:0)

好的,这真的不是一个答案,更多的是证明你推迟错误的推理

首先测试一个大字符串的写入速度

 import timeit
 def write_big_str(n_bytes=1000000):
     with open("test_file.txt","wb") as f:
          f.write("a"*n_bytes)
 print timeit.timeit("write_big_str()","from __main__ import write_big_str",number=100)

你应该看到一个相当可观的速度(并且重复它100次)

接下来我们将看到将一个非常大的数字转换为str

需要多长时间
import timeit,math
n = math.factorial(200000)
print timeit.timeit("str(n)","from __main__ import n",number=1)

它可能需要大约10秒(这是一个百万位数字),授予的速度很慢......但不是很慢的时间(好吧,它很慢转换为字符串:P ...但仍然不需要几个小时) (好吧我的盒子花了243秒钟,我想:P)