Каковы издержки передачи функций обратного вызова python в подпрограммы Fortran? - PullRequest
7 голосов
/ 23 сентября 2011

Я только что обернул подпрограмму Fortran 90 в python, используя F2PY.Тонкость здесь заключается в том, что подпрограмма Fortran также принимает функцию обратного вызова python в качестве одного из своих аргументов:

SUBROUTINE f90foo(pyfunc, a)
real(kind=8),intent(in) :: a
!f2py intent(callback) pyfunc
external pyfunc
!f2py real*8 y,x
!f2py y = pyfunc(x)

!*** debug begins***
print *, 'Start Loop'
do i=1,1000
  p = pyfunc(a)
end do
total = etime(elapsed)
print *, 'End: total=', total, ' user=', elapsed(1), ' system=', elapsed(2)
stop
!*** debug ends  ***

pyfunc - это функция python, определенная в другом месте моего кода на python.Обертка работает нормально, но, запустив обернутую версию выше, я получил в 5 раз больше времени, чем то, что я могу получить, используя чистый питон, следующим образом:

def pythonfoo(k):
    """ k: scalar 
        returns: scalar
    """
    print('Pure Python: Start Loop')
    start = time.time()
    for i in xrange(1000):
        p = pyfunc(k)
    elapsed = (time.time() - start)
    print('End: total=%20f'% elapsed)

Итак, вопрос в том, чтонакладные расходы?Я действительно хочу оставить pyfunc как есть, потому что перекодирование его в чисто фортран-функцию занимает очень много времени, так есть ли способ улучшить скорость модуля-обертки?

1 Ответ

9 голосов
/ 23 сентября 2011

В размещенном вами коде a - это число с плавающей запятой двойной точности.Передача его из Фортрана в Python означает перенос двойника Фортрана в объект PyFloat, который имеет свою стоимость.В чистой версии Python k - это PyFloat, и вы не платите цену за его завершение 1000 раз.

Другой проблемой является сам вызов функции.Вызов функций Python из C уже плох с точки зрения производительности, но вызов их из Fortran хуже, потому что есть дополнительный уровень кода для преобразования соглашений о вызовах функций Fortran (относительно стека и т. Д.) В соглашения о вызовах функций C.При вызове Python-функции из C вам необходимо подготовить аргументы как объекты Python, обычно создайте объект PyTuple, который будет служить аргументом * args функции Python, выполните поиск в таблице модуля для получения указателя на функцию...

И последнее, но не менее важное: вам нужно позаботиться о порядке расположения массивов при передаче 2D-массивов между Fortran и Numpy.F2py и numpy могут быть умными в этом отношении, но вы получите снижение производительности, если ваш код Python не написан для манипулирования массивами в порядке Фортрана.

Я не знаю, для чего предназначен pyfunc, но если он близок к тому, что вы опубликовали, написание цикла в Python и вызов функции только один раз сэкономит ваше время.И если вам нужны промежуточные значения (p), пусть ваша функция Python возвращает массив Numpy со всеми промежуточными значениями.

...