Действительно ли возможно использовать потоки для ускорения чтения файла?

Я хочу считать файл максимально быстро (40k строки) [Редактирование: остальное устаревшее].

Править: Andres Jaan Tack предложил решение на основе одного потока на файл, и я хочу быть уверенным, что я получил это (таким образом, это - самый быстрый путь):

  • Один поток на файл записи читает его целый и запасы его содержание в связанном контейнере (-> как много контейнеров, поскольку существуют файлы записи),
  • Один поток вычисляет линейную комбинацию каждой ячейки, считанной входными потоками и запасами результаты в контейнере выхода (связанный с выходным файлом).
  • Один поток пишет блоком (каждые 4 КБ данных, таким образом, приблизительно 10 строк) содержание выходного контейнера.

Я должен вывести, что не должен использовать m-отображаемые-файлы (потому что программа на резервном устройстве, ожидающем данных)?

Спасибо заблаговременно.

С уважением,

Господин mystère.

17
задан Mister Mystère 18 June 2010 в 12:19
поделиться

6 ответов

Ваш вопрос стал немного глубже, когда вы спросили дальше. Я постараюсь охватить все ваши варианты...

Чтение одного файла: сколько нитей?

Использовать одну нить.

Если вы читаете файл от начала до конца из одного потока, операционная система не будет получать файл небольшими фрагментами, как вы думаете. Скорее, она будет префетчить опережающий вас файл огромными (экспоненциально растущими) кусками, поэтому вы почти никогда не платите штраф за обращение к диску. Вы можете подождать диск несколько раз, но в целом это будет выглядеть так, как будто файл уже был в памяти, и это даже независимо от mmap.

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

Обратите внимание: Это еще до того, как вы добавите стоимость настройки потоков и всего остального. Это тоже что-то стоит, но это практически ничто по сравнению со стоимостью большего количества блокирующих обращений к диску.

Чтение нескольких файлов: Сколько потоков?

Используйте столько потоков, сколько у вас файлов (или какое-то разумное число).

Предварительная выборка файлов выполняется отдельно для каждого открытого файла. Когда вы начинаете читать несколько файлов, вы должны читать из нескольких из них параллельно. Это работает потому, что дисковый планировщик ввода-вывода попытается определить наиболее быстрый порядок чтения всех файлов. Часто дисковый планировщик есть как в ОС, так и на самом жестком диске. Тем временем префетчер может продолжать выполнять свою работу.

Параллельное чтение нескольких файлов всегда лучше, чем чтение файлов по одному. Если бы вы читали их по одному, ваш диск простаивал бы между префетчерами; это ценное время для чтения большего количества данных в память! Единственное, что может пойти не так, это если у вас слишком мало оперативной памяти для поддержки множества открытых файлов; но это уже не так часто встречается.

Слово предостережения: Если вы слишком усердствуете с чтением нескольких файлов, чтение одного файла начнет выбивать из памяти биты других файлов, и вы вернетесь к ситуации случайного чтения.

Объединение n файлов в один.

Обработка и получение вывода из нескольких потоков может работать, но это зависит от того, как вам нужно их объединить. В любом случае, вам придется быть осторожным с синхронизацией потоков, хотя наверняка есть относительно простые способы сделать это без блокировки.

Однако следует обратить внимание на одну вещь: Не утруждайте себя записью файла небольшими (< 4K) блоками. Собирайте по крайней мере 4К данных за раз, прежде чем вызывать write(). Кроме того, поскольку ядро заблокирует файл при записи, не вызывайте write() из всех ваших потоков вместе; все они будут ждать друг друга вместо того, чтобы обрабатывать больше данных.

26
ответ дан 30 November 2019 в 10:36
поделиться

Это проблема детализации. У вас небольшой файл, и вам нужно очень немного обработать. Один поток, вероятно, может проглотить весь файл за один временной интервал и обработать его в следующем. Два потока будут хуже, чем один. Прежде чем рассматривать параллелизм как решение для повышения производительности, вам потребуется гораздо более крупная задача.

1
ответ дан 30 November 2019 в 10:36
поделиться

[Изменить: исходный вопрос задан, если запуск до 40 000 потоков ускорит чтение файла]

То, что вы предлагаете, скорее всего, замедлит доступ из-за накладных расходов на создание потоков и контекста переключение. Больше потоков помогает только в том случае, если вы

1) вычислительно привязаны и у вас есть дополнительные ядра, которые могут помочь с работой

2) блокировка и другие потоки могут работать, ожидая разблокировки другими

3) у вас есть очень умный алгоритм, использующий поведение кеша

. Скорее всего, ваша скорость ограничена пропускной способностью диска и / или памяти, а не вычислительными пределами, поэтому один поток выполнения сможет максимально увеличить их.

18
ответ дан 30 November 2019 в 10:36
поделиться

Да, это пустая трата времени. В лучшем случае вы получите примерно ту же производительность. В худшем случае, это может снизить производительность из-за того, что диск обращается к разным частям файла вместо того, чтобы читать его последовательно.

4
ответ дан 30 November 2019 в 10:36
поделиться

В отличие от других читателей, я считаю, что теоретически может быть некоторая польза, даже если вы работаете на SP (однопроцессорной) системе. Однако я бы никогда не стал делать это для 40К строк (если вы говорите о строках нормального размера).

Ключевым является ответ Amardeep, где он говорит, что создание потоков полезно, когда поток становится заблокированным по какой-то причине.

Итак, как "работают" сопоставленные файлы? Когда вы впервые обращаетесь к странице памяти в этом регионе - процессор генерирует ошибку страницы. ОС загружает содержимое файла (для этого требуется доступ к диску) в страницу памяти. Затем выполнение возвращается к вашему потоку.

Я также полагаю, что при ошибке страницы ОС заполняет кучу последовательных страниц, а не только одну.

Теперь, что важно, во время обработки ошибки страницы ваш поток приостанавливается. Также в этот период процессор не загружен (не считая того, что могут делать другие процессы).

Таким образом, если вы посмотрите на шкалу времени, то увидите период из двух участков: один, где CPU загружен (здесь вы читаете содержимое страницы и выполняете некоторую обработку), и другой, где CPU почти простаивает и выполняется ввод-вывод на диск.

С другой стороны, вы можете создать несколько потоков, каждому из которых будет поручено чтение отдельной части файла. Вы получаете два эффекта:

  1. Другой поток имеет шанс загрузить центральный процессор (или несколько процессоров, если система MP), когда один из них заблокирован вводом/выводом.

  2. Даже в случае, когда обработка очень короткая (следовательно, CPU не является узким местом) - все равно есть выгода. Это связано с тем, что если вы выполняете несколько операций ввода-вывода на одном и том же физическом устройстве - у него есть шанс выполнить их более эффективно.

Например, при чтении множества различных секторов с диска HD вы можете прочитать их все за один оборот диска.

P.S.

И, конечно, я никогда не думал делать это для 40K строк. Накладные расходы на создание потоков, ожидание их завершения, переключение контекста, усложнение логики, обработка ошибок/неудач и т.д. и т.п.

Я бы попробовал сделать это для файла размером хотя бы в десятки мегабайт.

4
ответ дан 30 November 2019 в 10:36
поделиться

Я так думаю.

У вас 8 ядер, поэтому делайте 8 потоков. Пусть каждый поток анализирует один блок файла. Итак, вам нужно получить размер блока устройства / диска. Когда блок был проанализирован потоком, пусть поток проанализирует новый, еще не «назначенный» потоку.

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

Но это можно было бы превратить в состязание. Ничто не сравнится с настоящими живыми забегами! и люди вам покажут! :) найти подходящую цену!

-1
ответ дан 30 November 2019 в 10:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: