Некоторый контекст впереди того, откуда я. Фрагменты кода в конце.
По возможности я предпочитаю использовать инструмент с открытым исходным кодом, такой как H2O, для сверхвысокопроизводительного параллельного чтения файлов CSV, но этот инструмент имеет ограниченный набор функций. Я заканчиваю тем, что пишу много кода для создания конвейеров обработки данных, прежде чем передавать их в кластер H2O для собственно контролируемого обучения.
Я читал такие файлы, как набор данных HIGGS объемом 8 ГБ из репозитория UCI и даже файлы CSV размером 40 ГБ для целей науки о данных, значительно быстрее, добавляя много параллелизма с помощью объекта пула библиотеки многопроцессорной обработки и функции карты. Например, кластеризация с поиском ближайшего соседа, а также алгоритмы кластеризации DBSCAN и Маркова требуют некоторой тонкости параллельного программирования, чтобы обойти некоторые серьезные проблемы с памятью и временем настенных часов.
Обычно мне нравится разбивать файл по строкам на части, используя сначала инструменты gnu, а затем glob-filemask их все, чтобы найти и прочитать их параллельно в программе python. Обычно я использую около 1000+ частичных файлов. Выполнение этих трюков очень помогает с ограничениями скорости обработки и памяти.
Pandas dataframe.read_csv является однопоточным, поэтому вы можете использовать эти трюки, чтобы сделать pandas намного быстрее, запустив map () для параллельного выполнения. Вы можете использовать htop, чтобы увидеть, что с простыми старыми последовательными pandas dataframe.read_csv 100% ЦП только на одном ядре является фактическим узким местом в pd.read_csv, а не диском вообще.
Я должен добавить, что использую SSD на шине быстрой видеокарты, а не вращающийся HD на шине SATA6, плюс 16 ядер процессора.
Кроме того, я обнаружил, что еще один метод, который отлично работает в некоторых приложениях, - это параллельное чтение CSV-файла в одном гигантском файле, запуск каждого рабочего с разным смещением в файл, а не предварительное разбиение одного большого файла на несколько файлов частей. Используйте python file seek () и tell () в каждом параллельном работнике, чтобы читать большой текстовый файл полосами, в разных местах начального и конечного байта смещения байта в большом файле, все одновременно и одновременно. Вы можете выполнить регулярное выражение findall для байтов и вернуть количество переводов строки. Это частичная сумма. Наконец, просуммируйте частичные суммы, чтобы получить глобальную сумму, когда функция карты вернется после того, как рабочие закончили.
Ниже приведены несколько примеров тестов, использующих трюк с параллельным смещением байтов:
Использую 2 файла: HIGGS.csv - 8 Гб. Это из репозитория машинного обучения UCI. all_bin .csv составляет 40,4 ГБ и принадлежит моему текущему проекту. Я использую две программы: программу GNU wc, которая поставляется с Linux, и программу на чистом python fastread.py, которую я разработал.
HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv
HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb 2 09:00 all_bin.csv
ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496
real 0m8.920s
user 1m30.056s
sys 2m38.744s
In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175
Это примерно 4,5 ГБ / с, или 45 ГБ / с, при раздаче файлов. Это не вращающийся жесткий диск, мой друг. На самом деле это SSD Samsung Pro 950.
Ниже приведен тест скорости для того же файла, который подсчитывается с помощью gnu wc, программы, скомпилированной на чистом языке C.
Что круто, так это то, что вы можете видеть, что моя программа на чистом python в этом случае практически соответствовала скорости скомпилированной программы C, скомпилированной gnu wc. Python интерпретируется, но C скомпилирован, так что это довольно интересный подвиг скорости, я думаю, вы согласитесь. Конечно, wc действительно нужно преобразовать в параллельную программу, и тогда она действительно выбьет из моей программы на Python носки. Но в нынешнем виде gnu wc - это просто последовательная программа. Вы делаете то, что можете, и python сегодня может делать параллели. Компиляция Cython может мне помочь (в другой раз). Также еще не были исследованы файлы с отображением памяти.
HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv
real 0m8.807s
user 0m1.168s
sys 0m7.636s
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000
real 0m2.257s
user 0m12.088s
sys 0m20.512s
HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv
real 0m1.820s
user 0m0.364s
sys 0m1.456s
Вывод: скорость работы программы на чистом Python выше, чем у программы C. Однако этого недостаточно, чтобы использовать чистую программу Python поверх программы C, по крайней мере, для целей подсчета строк. Как правило, этот метод можно использовать для другой обработки файлов, поэтому этот код на Python все еще хорош.
Вопрос: Увеличивает ли скорость однократная компиляция регулярного выражения и его передача всем рабочим? Ответ: Предварительная компиляция Regex НЕ помогает в этом приложении. Я полагаю, причина в том, что накладные расходы на сериализацию и создание процессов для всех рабочих являются доминирующими.
Еще кое-что. Помогает ли параллельное чтение файла CSV? Узким местом является диск или процессор? Многие так называемые популярные ответы на stackoverflow содержат распространенную мудрость разработчиков, согласно которой вам нужен только один поток для чтения файла - лучшее, что вы можете сделать, говорят они. Но уверены ли они?
Давайте разберемся:
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000
real 0m2.256s
user 0m10.696s
sys 0m19.952s
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000
real 0m17.380s
user 0m11.124s
sys 0m6.272s
О да, да, это так. Параллельное чтение файлов работает неплохо. Ну вот, поехали!
Пс. В случае, если некоторые из вас хотели знать, что, если бы balanceFactor был равен 2 при использовании одного рабочего процесса? Что ж, это ужасно:
HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000
real 1m37.077s
user 0m12.432s
sys 1m24.700s
Ключевые части программы python fastread.py:
fileBytes = stat(fileName).st_size # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)
def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'): # counts number of searchChar appearing in the byte range
with open(fileName, 'r') as f:
f.seek(startByte-1) # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
bytes = f.read(endByte - startByte + 1)
cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
return cnt
Определение для PartitionDataToWorkers - это просто обычный последовательный код. Я оставил это на случай, если кто-то еще захочет попрактиковаться в параллельном программировании. Я раздал бесплатно самые сложные части: протестированный и работающий параллельный код для вашего обучения.
Спасибо: проекту H2O с открытым исходным кодом, выполненному Арно и Клиффом и сотрудниками H2O за их отличное программное обеспечение и обучающие видеоролики, которые послужили мне вдохновением для этого чистого высокопроизводительного параллельного считывателя байтов смещения на Python, как показано выше. H2O выполняет параллельное чтение файлов с использованием java, вызывается программами на Python и R и работает безумно быстро, быстрее, чем что-либо на планете, при чтении больших файлов CSV.
person
Geoffrey Anderson
schedule
02.02.2017