我对Python比较陌生,正在寻找用于旋转大型多维数组的最佳优化代码。在下面的代码中,我有一个16X600000个32位浮点多维数组,根据计时器,在四核AcerWindows8平板电脑上旋转内容大约需要30毫秒。我正在考虑使用一些Cython例程或类似的东西,如果有可能减少旋转数组所需的时间。在
最终,代码将用于存储基于VisPy包的高速数据绘图图形的y轴值,32位浮点数组将被传递给OpenGL例程。如果可能的话,我想达到1毫秒以下。在
任何意见,建议或示例代码将不胜感激。在
import sys, timeit
from threading import Thread
from PyQt4 import QtGui
import numpy as np
m = 16 # Number of signals.
n = 600000 # Number of samples per signal.
y = 0.0 * np.random.randn(m, n).astype(np.float32)
Running = False
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('Start', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
global Running, thread, thrTest
if Running == True:
Running = False
self.button.setText('Start')
thrTest.isRunning = False
print ('stop')
else:
Running = True
self.button.setText('Stop')
thrTest = testThread()
thread = Thread(target=thrTest.run, daemon=True )
thread.start()
print ("Start")
class testThread(Thread):
def __init__(self):
self.isRunning = True
def run(self):
print('Test: Thread Started')
while self.isRunning == True:
start_time = timeit.default_timer()
y[:, :-1] = y[:, 1:]
elapsed = timeit.default_timer() - start_time
print ('Time (s)= ' + str(elapsed))
print('Test: Closed Thread')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
我想我到底想做什么有点困惑,所以我会尽量解释得更好一些。在
最终的目标是要有一个快速的实时数据记录设备,在代表信号值的图形上画线。将有多个通道和采样率至少1ms和尽可能多的记录时间。我从this VisPy example开始。示例中将新数据写入数组并将其发送到OpenGL的代码位于底部附近的On_Timer
函数中。我稍微修改了这段代码,将OpenGL画布集成到Qt gui中,并添加了一些代码,通过以太网套接字从Arduino Mega获取数据。在
目前,我可以制作一个16行的实时图形,采样率约为1ms,帧速率约为30Hz,记录时间约为14秒。如果我再尝试增加通道数或记录长度,程序将停止工作,因为它无法跟上通过以太网端口以1ms速度传入的数据流
我能找到的最大的罪魁祸首是使用y[:, :-1] = y[:, 1:]
例程完成数据缓冲区移位所需的时间。最初,我提交了这个函数被计时的基准代码,希望有人知道一种更有效的方法来做同样的事情。这行代码的目的是将整个数组向左移动一个索引,然后在下一行代码中,我将新数据写入右侧的第一个插槽。在
下面你可以看到我修改后的图形更新程序。它首先从队列中获取新数据并解包到一个临时数组中,然后移动主缓冲区数组的内容,最后将新数据复制到主数组的最后一个插槽中。一旦队列为空,它将调用update函数,以便OpenGL更新显示。在
^{pr2}$
你真的想要这个吗?它将值左移,填充最后一列
对于这样的非标准“滚动”,不太可能有更快的东西。
^{pr2}$np.roll
左边有一个不同的填充就其价值而言,
roll
的核心是:你的特殊“卷”可以用类似的“take”复制
您的
y[:,:-1]...
比roll
快,因为它不创建新数组,而是覆盖现有数组的一部分。take
接受一个out
参数,因此这是可能的:虽然速度方面,这只对小数组有帮助。对于大的,你的重写任务更快。
我还建议使用转置,并在
axis=0
上滚动。对于order='C'
数组,行的值构成一个连续的块。最大的时间消耗者是您必须(几乎)将阵列的所有内容从一个位置复制到另一个位置,或者复制到新阵列中,或者复制到它本身。如果数据在某种环形缓冲区中,您只需更改指针,而不必复制任何数据。
正如其他人所提到的,我不认为你想改变CPU上的数组。每次更新时移动数组中的所有元素总是很慢的。我也不指望Cython能帮上忙,因为Numpy已经是最好的了。
相反,您需要处理顶点着色器中的移动。
我认为与您想要的类似的例子如下:http://vispy.org/examples/demo/gloo/realtime_signals.html编辑:一种方法是将VBO视为一个循环缓冲区。你可以在最旧的位置添加一个新的值。在http://vispy.org/examples/demo/gloo/spacy.html中使用了类似的技术
实时-信号.pyglumpy中的示例实现了一个环形缓冲区,可能有助于您:
https://github.com/glumpy/glumpy/blob/master/examples/realtime-signals.py
它很容易适应(而且很快就会适应)vispy。诀窍是使用类似Fortran的布局,这样更新16个信号就可以将一个连续的16个浮点块上传到GPU。这个例子应该处理你的16×600000数据,如果它适合GPU内存(只测试了16x100000的250fps)。
注意由于水平屏幕分辨率有限,这可能会阻止您看到整个数据(如果屏幕宽度为1600像素,则每个信号只显示1600个数据)。
相关问题 更多 >
编程相关推荐