2009-09-24 8 views
3

Мне нужно прочитать один файл, используя несколько потоков под Linux. Имеются только операции чтения и нет необходимости писать. Чтение файла не нужно читать весь файл каждый раз. Он должен каждый раз читать одну или несколько частей файла. Я хранил смещение каждой части заранее. Файл слишком большой, чтобы помещать его в основную память.Как повысить производительность чтения файлов несколькими потоками?

Так, например, многие пользователи хотят прочитать такой файл. Я использую поток или процесс для чтения файла для ответа на запросы пользователя. Что произойдет в Linux? Будут ли поставлены все операции чтения? И ОС завершит чтение файла один за другим? Возможно ли улучшить выполнение таких операций?

Я пытаюсь реализовать простой инвертированный индекс, используемый при поиске информации. Я помещаю словарь в память и публикую списки в файлах. Каждый файл содержит сегмент индекса. В словаре я могу хранить что-то вроде смещения, чтобы указать на позицию списка проводок слова. Когда 100 пользователей хотят что-то искать за одну секунду, они представляют разные запросы. Итак, каждое чтение будет читать другую часть файла.

+0

я сказал что-то не так, когда я спрашиваю. Чтение файла не нужно читать весь файл каждый раз. Он должен каждый раз читать одну или несколько частей файла. Я хранил смещение каждой части заранее. –

ответ

0

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

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

Однако все это догадка. Трудно дать достойный совет без дополнительной информации о приложении и файле, который он обрабатывает.

EDIT: на основе ваших последующих комментариев кажется, что нити не нуждаются во всех файлах. Мое первое предложение спорно (вы все готовы делать это!), И мое третье предложение не поможет. Я предлагаю вам сделать так, как @Jon Skeet говорит и реализует систему простым способом. Затем, если есть проблемы с производительностью, найдите способы сделать это быстрее/лучше. Например:

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

Я заимствовал интересный учебник по индексированию от коллеги пару лет назад. Я думаю, что это было Managing Gigabytes by Witten et al.

+0

Привет, я обновил вопрос и объяснил свое приложение. –

3

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

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

+6

Happy 100k !!! :-) –

1

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

Учитывая, что вы не можете извлечь выгоду из кэширования и не делиться прочитанной частью файла, вам нечего делать (просто прочитайте файл), но для улучшения вашей дисковой подсистемы: получите быстрые диски с большим количеством пропускная способность (RAID 10). Если этого недостаточно, сделайте две или более копий файла на разных логических дисках, чтобы еще больше увеличить пропускную способность.

+0

Я пытаюсь реализовать простой инвертированный индекс, используемый при поиске информации. Я помещаю словарь в память и публикую списки в файлах. Каждый файл содержит сегментирование индекса. В словаре я могу хранить что-то вроде смещения, чтобы указать на позицию списка проводок слова. Когда 100 пользователей хотят что-то искать, они представляют разные запросы. Таким образом, каждое чтение будет читать другую часть файла. Вы упомянули кэширование, но если словарь использует большую часть памяти, как будет выглядеть файл кеша Linux при условии, что файл большой. –

2

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

Что касается улучшения производительности, то в зависимости от данных и используемого алгоритма существует множество возможностей. Действительно ли необходимо, чтобы каждый поток читал весь файл для обслуживания каждого запроса? Зачем читать одни и те же данные снова и снова?Не можете ли вы централизовать часть информации, чтобы потоки могли делиться данными? Это похоже на дорогостоящее решение. И если вы много раз читаете файл, который больше, чем RAM, снова и снова, кэшированные блоки, которые имеют хороший шанс перечитать, могут быть вытолкнуты из кеша. Возможно, индекс файла может сэкономить вам некоторое время на чтение, и вы будете кэшировать доступ на основе индекса? Также рассмотрите возможность использования mmap() для сопоставления файла в память, тогда ОС будет вставлять и блокировать страницы в виде потоков, считанных из разных фрагментов. Поэтому стоит переосмыслить доступ к данным, только то, что вам нужно и когда. Если вы разместите здесь дополнительную информацию, люди могут предложить более конкретные предложения.

Помните, что самая эффективная операция - это тот, который вы не выполняете!

+0

Я сказал что-то не так, когда я спрашиваю. Чтение файла не нужно читать весь файл каждый раз. Он должен каждый раз читать одну или несколько частей файла. Я хранил смещение каждой части заранее. –

+0

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

2

Насколько велик ваш файл, который он не будет вписываться в память?

Было бы наиболее эффективно использовать p/s и использовать mmap(), чтобы отобразить файл в (виртуальную) память, а затем позволить потокам получить доступ к файлу через память. Если вы используете 32-битную машину, это ограничивает размер вашего файла «чем-то менее 4 ГБ, но, вероятно, более 2 ГБ»; если вы работаете на 64-битной машине, вы не ограничены, кроме дискового пространства.

Обратите внимание, что файл не обязательно должен находиться в физической памяти с mmap(); однако все это будет логически.

+0

Один файл может быть 2 ГБ, но как насчет 10 таких файлов? Например, осталась только свободная физическая память 2G. –

+0

На 32-битной машине вы снукер. На 64-битной машине o/s заботится о пейджинге файлов - биты, используемые в потоке, будут в памяти, а биты, которые не будут на диске. –

0

Очки следует отметить

  • Существует один драйвер, с одним приводом
  • И есть несколько (случайный) доступ из нескольких потоков

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

  • Увеличить приоритет вашего процесса (если это возможно), так что другие процессы не едят до процессорного времени
  • Выделяют планирование справедливого уровня между потоками
  • на основе хаотичности доступа (вы можете включить или отключить кэш)
    • Например, вы можете отключить кэш, если читает полностью случайным образом, и вы видите, что есть промах кэша в большинстве случаев