Найти - Пользователи
Полная версия: Оптимизация работы с arrays в ctypes
Начало » Python для новичков » Оптимизация работы с arrays в ctypes
1
Dmitri
Здравствуйте.
Есть плата обработки цифровых сигналов ‘ADLINK PCI-7200’ и C API для нее.
Результат чтения платой сигнала выдается в виде функции-прерывания.
На скрипт возлагается забача обработки результата.

class Dask:
	lib = ctypes.WinDLL('pci-dask.dll')
	card = None	# идентификатор платы
	size = 100000 # размер буффера чтения
	pmem = (ctypes.c_uint32 * 100000)() # буффер чтения
	rate = 500000.0 # опорная частота
	tm = None # структура синхронизации времени
class Clock( object ):
	def __init__( self, clock=None ):
		if clock:
			self.clock = clock
		else:
			self.clock = time.clock()
	def elapsed( self, clock=None ):
		if clock:
			return clock - self.clock
		return time.clock() - self.clock
Tm = collections.namedtuple('Tm', 'clock shots')
def handleTm():
	clock = time.clock()
	err = resultCast(Dask.lib.DI_AsyncDblBufferTransfer(Dask.card, ctypes.byref(Dask.pmem)))
	if err == 0:
		pmem = Dask.pmem
		clk = Clock()
		shots = makeShots(pmem)	# !!!
		print u'elapsed> makeShots: {elapsed}'.format(elapsed=clk.elapsed())
		if shots:
			Dask.tm = Tm(clock, shots)
Итак:
# (1) ~ 0.09 s
def makeShots( pmem ):
	ret = []
	for i in xrange(len(pmem)):
		if pmem[i] & 0x03:	# 1й канал чтение/запись
			ret.append(i)
	return ret

# (2) ~ 0.12 s
class Filter( object ):
	def __init__( self, pmem ):
		self.pmem = pmem
	def __call__( self, index ):
		return self.pmem[index] & 0x03
		
def makeShots_( pmem ):
	return filter(Filter(pmem), xrange(len(pmem)))

# (3) ~ 0.09 s
def makeShots__( pmem ):
	return [i for i in xrange(len(pmem)) if pmem[i] & 0x03]

Итого: 500000/100000 = 5 * ~0.1 = ~ 0.5s/1.0s

# (4) < 0.001 s
def makeShots___( pmem ):
	beg = 0
	end = len(pmem)
	ret = []
	while beg < end:
		beg = daskaux.findnextmask(ctypes.byref(pmem), beg, end, 0x03)
		if beg < end:
			ret.append(beg)
			beg += 1
	return ret

где daskaux.findnextmask - C функция
int findnextmask( U32* data, int beg, int end, U32 mask );

И главный вопрос - что делать, чтобы так не делать?
Dmitri
О данных:
Сигнал на плату идет с частотой 1Гц, т.е. 1 из 5 вызовов ‘handleTm’
Пример результата: Tm(clock=2.2130746798892735, shots=52991, 52992, 52993, 52994, 52995)
reclosedev
Действительно, как-то медленно работают ctypes array, медленнее простого Python списка.

Если я правильно понял, вам не хочется использовать дополнительные специализированные библиотеки с функциями (daskaux.findnextmask)?

Можно попробовать numpy (особенно если он уже есть в зависимостях проекта).
import numpy
 
def makeShots(pmem):
    arr = numpy.frombuffer(pmem, dtype=numpy.uint32)
    return numpy.where(arr & 0x03)[0]
Скорее всего это будет медленнее чем C функция из-за оверхеда на преобразование (это еще проверить нужно), но быстрее ctypes (проверено).
Dmitri
Да, хотелось бы не зарываться в С
Спасибо, проверю, отпишусь.
Dmitri
#(5) ~0.0015s
def makeShots(pmem):
	return list(numpy.where(numpy.frombuffer(pmem, dtype=numpy.uint32) & 0x03)[0])

Вельми гуд, хотя в логах тип numpy.array, а не list.
Ну да ладно, спасибо
Dmitri
def makeShots(pmem):
	return numpy.where(numpy.frombuffer(pmem, dtype=numpy.uint32) & 0x03)[0].tolist()
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB