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

Python中字符串到整数的快速转换,python,performance,optimization,Python,Performance,Optimization,实际上,一个简单的问题是:在TSV(制表符分隔值)文件中,有10亿(1e+9)个无符号32位整数存储为十进制ASCII字符串。与处理同一数据集的其他工具相比,使用int()。为什么?更重要的是:如何让它更快 因此,问题是:在Python中,将字符串转换为整数的最快方法是什么 我真正想的是一些半隐藏的Python功能,可以(ab)用于此目的,这与Guido在他的文章中使用的array.array没有什么不同 示例数据(选项卡扩展到空格) 读取数据所需的时间与此无关,处理数据是瓶颈 微基准点 以下所

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

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

我真正想的是一些半隐藏的Python功能,可以(ab)用于此目的,这与Guido在他的文章中使用的
array.array
没有什么不同

示例数据(选项卡扩展到空格)

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

微基准点

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

Python为0.9.1的Python 2.6.2,每秒约214k次转换(100%):

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

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

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

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


我可能会建议,对于原始速度,Python并不是完成此任务的合适工具。手工编码的C实现将轻松击败Python。

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

这可能不是您的选择,但我会认真考虑使用二进制文件而不是文本。它经常变化吗?如果没有,您可以对其进行预处理。

通过确保在最紧密的循环中只使用“局部”变量,您将获得一定的速度百分比。
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)))

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

你可以阅读更多关于,看看这是否会有帮助


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

以下最简单的C扩展已经大大改进了内置的功能,能够每秒转换三倍多的字符串(650kcps vs 214kcps):


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

numpy做得很好:


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

我完全同意,但这不是我问题的重点。我加了一段我要找的东西。不过,自定义Python扩展也是一种选择。尝试
numpy.fromfile
加载“十亿个正整数”(顺便问一下,“十亿”是什么意思(在美国是
10**9
,在英国可能是
10**12
)?关于十亿的好消息;尽管后者在20世纪70年代在英国已不再流行。您是否尝试编译代码?(1)请比“存储为文本文件中的ASCII字符串”更明确。固定列或分隔列?这是文件中唯一的数据类型吗?显示一些示例行。(2)向我们展示您当前使用的代码,如果您想让我们相信int()是问题所在,并且这不是一个家庭作业问题(3)请用SI单位表示速度,而不是“非常慢”。(4)其他什么工具?(5)什么平台和Python的什么版本?(6)整数的平均位数是多少?(7)数字是十进制/十六进制/八进制/其他吗?-解释==>慢速推论上的1。在这种情况下,C实现会更快,但您的泛化是完全错误的。在执行时,解释语言必须翻译成机器代码,这比执行编译的目标代码要慢。仍然不要理解还有你的反对票。请解释为什么你认为“我的概括”是错误的。解释语言可以在运行时对字节码进行优化,有时会导致比本机代码更好的性能。查找它,它已经被讨论到了极点。嗯,我想90%的情况不足以概括,所以它是经过编辑的。尽可能地从内部循环中移出,然后
>> 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
>> 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
q)strings:string til "i"$1e7

q)\t "I"$strings
496
values = map(int, open("numberfile.txt"))
numfile = open("numberfile.txt")
valIter = itertools.imap(int, itertools.chain(itertools.imap(str.split, numfile)))
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);
}