Разгон по левой полосе.
Мы проводим много времени в ожидании завершения некоторой задачи по подготовке данных - вы бы сказали, что это удел специалистов по данным. Что ж, мы можем ускорить процесс. Вот два метода, которые вам пригодятся: файлы с отображением памяти и многопоточность.
Данные
Недавно мне пришлось извлекать термины и их частоту из Корпуса Google Книг Ngram, и я задумался, есть ли способы ускорить выполнение задачи. Корпус состоит из двадцати шести файлов общим объемом 24 ГБ. Каждый из интересующих меня файлов содержит термин и другие метаданные, разделенные табуляцией. Подход грубой силы к чтению этих файлов как фреймов данных pandas был… медленным. Поскольку нам нужны были только уникальные термины и их количество совпадений, я подумал, что постараюсь сделать это быстрее :-)
Файлы с отображением памяти
Эта техника не нова. Он существует уже давно и возник в Unix (до Linux!). Вкратце, mmap
обходит обычную буферизацию ввода-вывода, загружая содержимое файла в страницы памяти. Это очень хорошо работает для компьютеров с большим объемом памяти. Это в основном нормально для современных настольных компьютеров и ноутбуков, где 32 ГБ памяти больше не относятся к сфере эзотерики. Библиотека Python имитирует большую часть функций Unix и предлагает удобную функцию readline()
для извлечения байтов по одной строке за раз.
# map the entire file into memory mm = mmap.mmap(fp.fileno(), 0) # iterate over the block, until next newline for line in iter(mm.readline, b""): # convert the bytes to a utf-8 string and split the fields term = line.decode("utf-8").split("\t")
fp
- это указатель на файл, который ранее был открыт с атрибутом доступа r+b
. Итак, с помощью этой простой настройки вы сделали чтение файлов в два раза быстрее (ну, точное улучшение будет зависеть от многих вещей, таких как HW диска и т. Д.).
Многопоточность
Следующий метод, который всегда помогает ускорить работу, - это добавление параллелизма. В нашем случае задача была связана с вводом-выводом. Это хорошо подходит для увеличения масштаба - т. Е. добавления потоков. Вы найдете хорошие дискуссии о том, когда лучше выполнять горизонтальное масштабирование (множественную обработку) в поисковых системах.
Python3 имеет отличную стандартную библиотеку для управления пулом потоков и динамического назначения им задач. И все это с невероятно простым API.
# use as many threads as possible, default: os.cpu_count()+4 with ThreadPoolExecutor() as threads: t_res = threads.map(process_file, files)
Значение по умолчанию max_workers
для ThreadPoolExecutor
- 5 потоков на ядро ЦП (начиная с Python v3.8). map()
API получит функцию, которая будет применяться к каждому члену списка, и запустит функцию автоматически, когда потоки станут доступными. Вот это да. Так просто. Менее чем за пятьдесят минут я преобразовал входные 24 ГБ в удобный набор данных 75 МБ для анализа с помощью pandas - вуаля.
Полный код находится на GitHub. Комментарии и замечания всегда приветствуются.
PS: Я добавил индикатор выполнения с tqdm
для каждого потока. Я действительно не знаю, как им удается избежать зацикливания строк на экране ... Работает как шарм.
Обновление: я только что узнал о библиотеке vaex. Он реализует отображение памяти из коробки. Выглядит отлично.