如何使用Cython加速python中的循环

时间:2014-11-20 16:23:44

标签: python performance time-complexity cython beagleboneblack

我正在尝试使用Beaglebone Black(BBB)和Python制作传感器。我需要从传感器每秒获得尽可能多的数据。下面的代码允许我每秒收集大约100,000个数据点。

import Adafruit_BBIO_GPIO as GPIO
import time 

GPIO.setup("P8_13", GPIO.IN)

def get_data(n):
    my_list = []
    start_time = time.time()
    for i in range(n):
        my_list.append(GPIO.input("P8_13"))
    end_time = time.time() - start_time
    print "Time: {}".format(end-time)
    return my_list

n = 100000
get_data(n)

如果n = 1,000,000,填充my_list大约需要10秒,当n = 100,000且time = 1s时,这个速率相同。

我决定尝试使用Cython来获得更好的效果。我听说它可以显着加快python代码。我按照基本的Cython教程:使用上面的python代码创建了data.pyx文件,然后创建了一个setup.py,最后构建了Cython文件。

不幸的是,这根本没有帮助我。所以,我想知道我是否使用Cython不当或在这种情况下,当没有"繁重的数学计算"时,Cython不能帮助太多。任何关于如何加速我的代码的建议都非常感谢!

2 个答案:

答案 0 :(得分:2)

您可以从添加静态类型声明开始:

import Adafruit_BBIO_GPIO as GPIO
import time 

GPIO.setup("P8_13", GPIO.IN)

def get_data(int n):  # declared as an int
    my_list = []
    start_time = time.time()
    for i in range(n):
        my_list.append(GPIO.input("P8_13"))
    end_time = time.time() - start_time
    print "Time: {}".format(end-time)
    return my_list

n = 100000
get_data(n)

这允许循环本身转换为纯C循环,缺点是n不再是任意精度(所以如果你试图传递一个大于20亿的值,你会得到未定义的行为)。将int更改为unsigned long long可以减轻此问题,unsigned允许的值最高为2 ** 64 - 1,或大约为18 quintillion。 {{1}}量词表示您无法传递负值。

如果您可以删除列表,您将获得更大幅度的提升速度。尝试用array替换它。 Cython可以work more efficiently with arrays than with lists

答案 1 :(得分:0)

我尝试了相同的代码,但使用了不同版本的Adafruit_BBIO, 在我的rev C板上运行一百万次只需要3秒钟。

我认为从Rev B到Rev C的主板变化是eMMC从2GB增加到4GB。

如果您去获取当前的Adafruit_BBIO,您在上面的代码中需要更改的是第一个导入语句,它应该是Adafruit_BBIO.GPIO as GPIO

你接下来尝试了什么?

罗恩