Повышение производительности функции Cython для более быстрого чтения файлов

#performance #cython

#Производительность #cython

Вопрос:

Я пытаюсь прочитать файл ascii (текстовый) определенного формата. Я выполнил некоторое профилирование строк, и запись времени используется в цикле. Я пытаюсь, можно ли улучшить производительность кода внутри цикла.

Что я пробовал

  1. Более быстрая индексация массива numpy путем инициализации массива numpy с интерфейсом буфера, как в официальных документах, что, как я ожидал, значительно ускорит процесс, но едва ли что-то изменило.

  2. Пользовательская функция преобразования типов (без взаимодействия с python) для замены int (строка [0: 5]), но это оказалось довольно дорогостоящим

Пользовательская функция для преобразования типов

 cdef int fast_atoi(str buf):
    cdef int i=0 ,c = 0, x = 0
    for i in range(5):
        c = buf[i]
        if c > 47 and c < 58:
            x = x * 10   c - 48
    return x
  

Основной блок кода, который я хочу оптимизировать

 def func(filename):
        cdef np.ndarray[np.int32_t] a1
        cdef np.ndarray[object] a2
        cdef np.ndarray[object] a3
        cdef np.ndarray[np.int32_t] a4
        cdef int count = 0
        cdef int n_lines
        cdef str line
        with open(filename) as inf:
            next(inf)
            n_lines = int(next(inf))
            a1 = np.zeros(n_atoms, dtype=np.int32)
            a2 = np.zeros(n_atoms, dtype=object)
            a3 = np.zeros(n_atoms, dtype = object)
            a4 =  np.zeros(n_atoms, dtype=np.int32)
            for i,line in enumerate(inf):
                if i == n_lines:
                    break
                try:
                    a1[i] =  int(line[0:5]) #custom function fast_atoi(line[0:5])
                    a2[i] = line[5:10].strip()
                    a3[i] = line[10:15].strip()
                    a4[i] = int(line[15:20])
                except (ValueError, TypeError) as e:
                    break

  

У меня есть файл размером 4,3 МБ

 Author
n_lines
    1xyz      A    1   5.202   4.356   3.155
    1mno     A1    2   5.119   4.411   3.172
    1mno     A2    3   5.155   4.283   3.104
    1nnn     B3    4   5.247   4.318   3.237
    1xax     KA    5   5.306   4.421   3.075
    1ooo     MA    6   5.383   4.347   3.054
    1cbd     NB    7   5.257   4.474   2.941
    1orc     OB1   8   5.189   4.404   2.893
  

Текущая реализация занимает в среднем 76 мс на моем компьютере, добавление упомянутой пользовательской функции ухудшает ситуацию.

Я был бы очень признателен, если бы можно было предложить некоторые улучшения. Я новичок в cython.

Комментарии:

1. Вы пробовали pandas программу чтения CSV?

2. Да, просто дороже. Поскольку при чтении файла выполняется обработка строк, считывается файл, который не является таким прямым при чтении pandas.

3. Вероятно, вы хотите отключить проверку границ для своей функции. Также может потребоваться преобразовать ваш str в массив символов, я не знаю, если cython автоматически оптимизирует доступ к строке python. Вы можете получить аннотированный отчет от компилятора cython с помощью cython -a , любые строки, выделенные желтым в отчете, имеют некоторые накладные расходы python, от которых вы захотите избавиться.

4. Спасибо за предложения @ngoldbaum.