我有一个分析代码,使用numpy进行了一些繁重的数值运算。出于好奇,尝试使用cython对其进行几乎没有任何更改的编译,然后使用numpy部分的循环将其重写。
令我惊讶的是,基于循环的代码要快得多(8倍)。我无法发布完整的代码,但是我将一个非常简单的不相关的计算放在一起,显示出相似的行为(尽管时间差异不是很大):
版本1(无cython)
import numpy as np
def _process(array):
rows = array.shape[0]
cols = array.shape[1]
out = np.zeros((rows, cols))
for row in range(0, rows):
out[row, :] = np.sum(array - array[row, :], axis=0)
return out
def main():
data = np.load('data.npy')
out = _process(data)
np.save('vianumpy.npy', out)
版本2(使用cython构建模块)
import cython
cimport cython
import numpy as np
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef _process(np.ndarray[DTYPE_t, ndim=2] array):
cdef unsigned int rows = array.shape[0]
cdef unsigned int cols = array.shape[1]
cdef unsigned int row
cdef np.ndarray[DTYPE_t, ndim=2] out = np.zeros((rows, cols))
for row in range(0, rows):
out[row, :] = np.sum(array - array[row, :], axis=0)
return out
def main():
cdef np.ndarray[DTYPE_t, ndim=2] data
cdef np.ndarray[DTYPE_t, ndim=2] out
data = np.load('data.npy')
out = _process(data)
np.save('viacynpy.npy', out)
版本3(使用cython构建模块)
import cython
cimport cython
import numpy as np
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef _process(np.ndarray[DTYPE_t, ndim=2] array):
cdef unsigned int rows = array.shape[0]
cdef unsigned int cols = array.shape[1]
cdef unsigned int row
cdef np.ndarray[DTYPE_t, ndim=2] out = np.zeros((rows, cols))
for row in range(0, rows):
for col in range(0, cols):
for row2 in range(0, rows):
out[row, col] += array[row2, col] - array[row, col]
return out
def main():
cdef np.ndarray[DTYPE_t, ndim=2] data
cdef np.ndarray[DTYPE_t, ndim=2] out
data = np.load('data.npy')
out = _process(data)
np.save('vialoop.npy', out)
将10000x10矩阵保存在data.npy中,时间为:
$ python -m timeit -c "from version1 import main;main()"
10 loops, best of 3: 4.56 sec per loop
$ python -m timeit -c "from version2 import main;main()"
10 loops, best of 3: 4.57 sec per loop
$ python -m timeit -c "from version3 import main;main()"
10 loops, best of 3: 2.96 sec per loop
这是预期的还是我缺少的优化?版本1和版本2给出相同结果的事实在某种程度上是可以预期的,但是为什么版本3更快?
附言:-这不是我需要进行的计算,只是一个简单的示例即可显示相同的内容。
如其他答案中所述,版本2与版本1本质上相同,因为cython无法深入研究数组访问运算符以对其进行优化。有两个原因
首先,与优化的C代码相比,每次调用numpy函数都会有一定的开销。但是,如果每个操作处理大型数组,则此开销将变得不那么重要
其次,创建中间数组。如果您考虑使用更复杂的操作(例如),则更清楚out[row, :] = A[row, :] + B[row, :]*C[row, :]
。在这种情况下,B*C
必须在内存中创建整个数组,然后将其添加到中A
。这意味着CPU缓存正在被破坏,因为数据是从内存中读取和写入到内存中,而不是直接保存在CPU中并立即使用。重要的是,如果要处理大型阵列,此问题将变得更加严重。
特别是由于您声明实际代码比示例复杂,并且显示出更大的加速性,因此我怀疑第二个原因很可能是您的案例中的主要因素。
顺便说一句,如果您的计算足够简单,则可以使用numexpr克服这种影响,尽管cython当然在更多情况下很有用,所以它可能是您的更好方法。
通过速度/步速区,您可以在训练课中轻松监控速度或步速,并调整速度/步速,以达到目标训练效果。这些区域可以用来指导您在训练课期间的训练效率,并帮助您组合与不同的训练强度,以获得最佳效果。 速度区设置 可以在 Flow 网络服务上调整速度区设置。有五个不同的速度区,您可手动调整速度限制,或使用默认区。速度区特定于运动,您可以加以调整,以最佳适合每项运动。这些区域可用于跑步运动(包括涉及跑步的团队运动)
通过速度/步速区,您可以在训练课中轻松监控速度或步速,并调整速度/步速,以达到目标训练效果。这些区域可以用来指导您在训练课期间的训练效率,并帮助您组合与不同的训练强度,以获得最佳效果。 速度区设置 可以在 Flow 网络服务上调整速度区设置。有五个不同的速度区,您可手动调整速度限制,或使用默认区。速度区特定于运动,您可以加以调整,以最佳适合每项运动。这些区域可用于跑步运动(包括涉及跑步的团队运动)
问题内容: 哪一个更好?使用如下速记: 或像这样长手: 相关: 性能(浏览器性能,文件大小) 文档(开发人员易于维护) 和别的 问题答案: 除非您已概要分析页面加载并且它已成为瓶颈,否则您不必担心CSS性能(我怀疑,它几乎总是多个HTTP请求和图像)。 任何有能力的开发人员都可以从上到下顺时针记住值的顺序。 速记意味着要发送的字节数更少,CSS缩小器并不会优化自身(我不认为)。 如果设置一个值,例
问题内容: 我已经在Scala中编程了一段时间了,我喜欢它,但是令我烦恼的是编译程序所花费的时间。这似乎是一件小事,但是使用Java可以对程序进行一些小的更改,单击netbeans中的运行按钮,然后BOOM就会运行,随着时间的推移,在scala中进行编译似乎会花费大量时间。我听说在许多大型项目中,脚本编写语言变得非常重要,因为需要花费大量的编译时间,而使用Java时却没有看到这种需求。 但是我来自
比赛速度功能有助于您保持稳定配速,并在设定距离内达到您的目标时间。定义某段距离的目标时间 - 例如将 10 公里跑步的目标时间设定为 45 分钟,并跟踪对比实际用时与这个预设目标的差距。 您可以在手表上设置比赛速度,或者可以在 Flow 网络服务或应用程序中设置比赛速度目标,并同步至手表。 如果您已计划好当天的比赛速度目标,手表会在进入训练准备模式时建议您启动该目标。 在手表上创建比赛速度目标 您
比赛速度功能有助于您保持稳定配速,并在设定距离内达到您的目标时间。定义某段距离的目标时间 - 例如将 10 公里跑步的目标时间设定为 45 分钟,并跟踪对比实际用时与这个预设目标的差距。 您可以在手表上设置比赛速度,或者可以在 Flow 网络服务或应用中设置比赛速度目标,并同步至手表。 如果您已计划好当天的比赛速度目标,手表会在进入训练准备模式时建议您启动该目标。 在手表上创建比赛速度目标 您可以
我目前正在开发一个应用程序,它应该通过设备的加速度来计算速度。为了实现这一点,我使用传感套件。应用程序记录用户运动的数据并将其保存到本地存储器。当用户停止记录时,可以按时间以速度绘制收集的加速度(加速度计的每个轴有三个曲线图)。 检测工具包使用CMMotionManager的startAccelerometerUpdates获取加速度。为了计算速度,我做了一些信号处理和加速度的积分(然后乘以9.8
本文向大家介绍Redis利用Pipeline加速查询速度的方法,包括了Redis利用Pipeline加速查询速度的方法的使用技巧和注意事项,需要的朋友参考一下 1. RTT Redis 是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下 Redis 客户端执行一条命令分为如下四个过程: 发送命令 命令排队 命令执行 返回结果 客户端向服务端发送一个查询请求,并监听Soc