Python中的快速字符串到整数转换

时间:2009-08-20 22:11:33

标签: python performance optimization

一个简单的问题,实际上:在TSV(制表符分隔值)文件中,您有十亿(1e + 9)个无符号32位整数存储为十进制ASCII字符串。与使用同一数据集的其他工具相比,使用int()进行转换的速度非常慢。为什么?更重要的是:如何让它更快?

因此问题是:在Python中将字符串转换为整数的最快方法是什么?

我真正想到的是一些半隐藏的Python功能,可以(ab)用于此目的,与Guido在"Optimization Anecdote"中使用array.array不同。

示例数据(标签扩展为空格)

38262904        "pfv"              2002-11-15T00:37:20+00:00
12311231        "tnealzref"        2008-01-21T20:46:51+00:00
26783384        "hayb"             2004-02-14T20:43:45+00:00
812874          "qevzasdfvnp"      2005-01-11T00:29:46+00:00
22312733        "bdumtddyasb"      2009-01-17T20:41:04+00:00

读取数据所花费的时间与此无关,处理数据是瓶颈。

微基准

以下所有语言均为解释语言。主机正在运行64位Linux。

使用IPython 0.9.1的Python 2.6.2,每秒约214k转换(100%):

In [1]: strings = map(str, range(int(1e7)))

In [2]: %timeit map(int, strings);
10 loops, best of 3: 4.68 s per loop

REBOL 3.0版本2.100.76.4.2,~231kcps(108%):

>> strings: array n: to-integer 1e7 repeat i n [poke strings i mold (i - 1)]
== "9999999"

>> delta-time [map str strings [to integer! str]]
== 0:00:04.328675

REBOL 2.7.6.4.2(2008年3月15日),约523kcps(261%):

正如John在评论中指出的那样,这个版本构建转换整数的列表,因此给出的速度比是相对于for str in strings: int(str)的Python的4.99s运行时。

>> delta-time: func [c /local t] [t: now/time/precise do c now/time/precise - t]

>> strings: array n: to-integer 1e7 repeat i n [poke strings i mold (i - 1)]
== "9999999"

>> delta-time [foreach str strings [to integer! str]]
== 0:00:01.913193

KDB + 2.6t 2009.04.15,~2016kcps(944%):

q)strings:string til "i"$1e7

q)\t "I"$strings
496

7 个答案:

答案 0 :(得分:3)

我可能会建议,对于原始速度,Python不适合执行此任务。手动编码的C实现将轻松击败Python。

答案 1 :(得分:3)

通过确保在最严格的循环中仅使用“本地”变量,您将获得一定比例的速度。 int函数是全局函数,因此查找它将比本地函数更昂贵。

你真的需要内存中的所有十亿个数字吗?考虑使用一些迭代器一次只给你几个值。十亿个数字会占用一些存储空间。将这些附加到列表中,一次一个,将需要几次大的重新分配。

如果可能的话,完全从Python中循环出来。这里的地图功能可以是你的朋友。我不确定您的数据是如何存储的。如果每行只有一个数字,则可以将代码减少到

values = map(int, open("numberfile.txt"))

如果每行有多个值是空格分隔的,请深入研究itertools以保持循环代码不受Python影响。这个版本还有一个额外的好处,就是创建一个数字迭代器,这样你就可以一次只从文件中取出一个或多个数字,而不是一次性使用10亿个。

numfile = open("numberfile.txt")
valIter = itertools.imap(int, itertools.chain(itertools.imap(str.split, numfile)))

答案 2 :(得分:3)

以下最简单的C扩展已经大大改进了内置,管理转换速度超过每秒三倍的字符串(650kcps vs 214kcps):

static PyObject *fastint_int(PyObject *self, PyObject *args) {
    char *s; unsigned r = 0;
    if (!PyArg_ParseTuple(args, "s", &s)) return NULL;
    for (r = 0; *s; r = r * 10 + *s++ - '0');
    return Py_BuildValue("i", r);
}

这显然不适合任意长度的整数和其他各种特殊情况,但在我们的场景中没有问题。

答案 3 :(得分:1)

同意格雷格; Python作为一种解释语言通常很慢。您可以尝试使用Psyco library动态编译源代码,或者使用较低级别的语言(如C / C ++)对应用程序进行编码。

答案 4 :(得分:1)

正如其他人所说,您可以编写自己的C模块来为您进行解析/转换。然后你可以简单地导入它并调用它。您可以使用Pyrex或其Cython衍生物从Python生成C(通过向Python添加一些类型约束提示)。

您可以阅读有关Cython的更多信息,看看是否有帮助。

我想到的另一个问题是......你将用这十亿个整数做什么?是否有可能将它们作为字符串加载,将它们作为字符串搜索并根据需要执行延迟转换?或者您可以使用threadingmultiprocessing模块和队列并行转换和其他计算吗? (让一个或多个线程/进程执行转换并提供处理引擎从中获取它们的队列)。换句话说,生产者/消费者设计会缓解这个问题吗?

答案 5 :(得分:0)

它可能不是你的选择,但我会非常努力地使用二进制文件而不是文本。它经常变化吗?如果没有,你可以预先处理它。

答案 6 :(得分:0)

numpy的这一点做得很好:

np.fromstring(line,dtype = np.float,sep =“”)

相关问题