Уведомления

Группа в Telegram: @pythonsu

#1 Март 15, 2020 20:12:18

maksimio
Зарегистрирован: 2020-03-15
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

Здравствуйте, возникла следующая проблема: я не могу понять, как правильно с помощью ctypes передать в C-функцию двумерный массив из python, размер которого задается во время выполнения python-скрипта. В функции требуется изменить элементы двумерного массива. Гугление помогло найти лишь передачу одномерного массива в функцию - это сработало. Но как реализовать мой случай я не понимаю.

Вот пример функции на C, которую требуется вызвать из кода на python. Она перед этим компилируется в динамическую библиотеку.

 void changeArray(int arrayLen_1, int arrayLen_2, int **array)
{
    for (int i = 0; i < arrayLen_1; i++)
        for (int j = 0; j < arrayLen_2; j++)
            array[i][j] = j+i;  
}

Офлайн

#2 Март 15, 2020 22:32:04

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

maksimio
void changeArray(int arrayLen_1, int arrayLen_2, int **array)
С такой сигнатурой это вовсе не двумерный массив. Передать то не проблема. Но изготовить такую штуку в питоне будет ой как непросто.

Приведите код на питоне которым вы собрались создавать этот “двумерный массив”.



Офлайн

#3 Март 16, 2020 00:15:08

maksimio
Зарегистрирован: 2020-03-15
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

Двумерные массивы планировал создавать следующим образом:

 a = 56
b = 4
array = [[0 for i in range(a)] for k in range(b)]

Сейчас я решил свою проблему, сколхозив передачу нескольких одномерных массивов в C-функцию. Пока это сгодится, но мне желательно бы иметь возможность изменять произвольное количество массивов, а не 8, как в коде ниже.

Код на Python функции, которая собирает C-функцию с помощью ctypes:
 def read_csi(csi_buf, nr, nc, num_tones):
    '''Расшифровывает csi из csi_buf, вызывая с помощью ctypes C-функцию'''
    if nr != 2 or nc != 2 or num_tones != 56:
        raise TypeError("Error: nr != 2 or nc != 2 or num_tones != 56")
    csi_re = [[0 for i in range(num_tones)] for k in range(nr * nc)]
    csi_im = [[0 for i in range(num_tones)] for k in range(nr * nc)]
    lib = ctypes.CDLL('./libextract_csi.so')
    lib.read_csi.restype = None
    lib.read_csi.argtypes = (ctypes.POINTER(ctypes.c_ubyte), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(
        ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
    csi_buf = (ctypes.c_ubyte * len(csi_buf))(*csi_buf)
    for i in range(nr*nc):
        csi_re[i] = (ctypes.c_int * len(csi_re[i]))(*csi_re[i])
        csi_im[i] = (ctypes.c_int * len(csi_im[i]))(*csi_im[i])
    lib.read_csi(csi_buf, csi_re[0], csi_re[1],
                 csi_re[2], csi_re[3], csi_im[0], csi_im[1], csi_im[2], csi_im[3])
    csi_re[0], csi_re[1], csi_re[2], csi_re[3] = csi_re[0][:], csi_re[1][:], csi_re[2][:], csi_re[3][:]
    csi_im[0], csi_im[1], csi_im[2], csi_im[3] = csi_im[0][:], csi_im[1][:], csi_im[2][:], csi_im[3][:]
    return {'re': csi_re, 'im': csi_im}


Код C-функции:
void read_csi(unsigned char *local_h, int *re0, int *re1, int *re2, int *re3, int *im0, int *im1, int *im2, int *im3)
{

//здесь происходит изменение содержимого всех массивов re и im на основании данных из local_h
}

Офлайн

#4 Март 16, 2020 06:48:52

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

maksimio
Сейчас я решил свою проблему
Очевидно вы ее не решили поскольку решение не соответствует требованиям первого поста.
В С не бывает двумерных массивов с переменными размерностями. Поэтому чисто формально передать туда такое нельзя.

Точнее непонятно в чем ваша проблема.
Это учебная задача? Нет -тогда нельзя менять интерфейс.
Вы хотите повысить быстродействие? Нет. Очевидно что все ваши манипуляции с массивами сожрут производительность. Тогда вы бы работали с данными лежащими в памяти подряд. Те нельзя работать со списками питона. Вместо них надо либо struct использовать либо что-то типа (ctypes.c_int*3)*5 либо numpy.array.
Вы делаете интерфейс к готовой системе? Нет. Сложность зашкаливает. В этом случае вы бы использовали boost python, pybind11, swig, cython или другие средства для этого предназначенные.



Офлайн

#5 Март 17, 2020 16:59:05

maksimio
Зарегистрирован: 2020-03-15
Сообщения: 3
Репутация: +  0  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

Моя цель - повысить производительность. Время которое сожрут списки несущественно относительно времени, которое экономится, если C-функцию запускать с помощью ctypes (проверено профилировщиком). Я пробовал переписать эту функцию на python и не вызывать ее как dll - тогда код работает в 5 раз дольше.

Сейчас я просто хотел бы понять, каким образом я могу подать в C-функцию с помощью ctypes двумерный (а еще лучше многомерный) массив (т.е. массив указателей на указатели в C-функции). Я не знаю, с помощью какого типа данных в python это лучше сделать. У меня мало опыта, поэтому я был бы рад, если бы вы посоветовали что-то на этот счет. Либо я просто по прошествии некоторого времени смогу найти в интернете, как это можно сделать.

Офлайн

#6 Март 17, 2020 20:46:48

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

maksimio
каким образом я могу подать в C-функцию с помощью ctypes двумерный (а еще лучше многомерный) массив (т.е. массив указателей на указатели в C-функции)

Вы наверное не очень хорошо знаете C. Поэтому я еще раз вам повторю. Двумерный массив и массив указателей на указатели это совершенно разные типы.

Для первого посоветую https://docs.scipy.org/doc/numpy-1.9.2/reference/generated/numpy.ndarray.ctypes.html

Для второго нормальных аналогов в питоне нет.



Офлайн

#7 Март 17, 2020 23:31:40

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10031
Репутация: +  857  -
Профиль   Отправить e-mail  

ctypes - как изменить в функции содержимое двумерного массива?

maksimio
Моя цель - повысить производительность.
Напиши, какую программу делаешь. Неглубокое знание языка C и неглубокое знания языка Python вряд ли приведут к успеху. Так что, если у тебя и программа не сделана ещё, то заниматься повышением её производительности считается ошибкой, которая называется “преждевременная оптимизация”.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version