2009-10-10 3 views
7

Что такое эффективный способ для многопоточного приложения Java, где многие потоки должны читать один и тот же файл (размером> 1 ГБ) и выставлять его как входной поток? Я заметил, что если есть много потоков (> 32), система начинает бороться с I/O и ожидает много ожидающих операций ввода-вывода.Java многопоточность чтения одного большого файла

Я рассмотрел загрузку файла в массив байтов, общий для всех потоков - каждый поток создавал ByteArrayInputStream, но выделение массива в 1 Гбайт просто не будет работать.

Я также рассмотрел использование одного FileChannel и каждого потока, создающего InputStream поверх него с помощью Channels.newInputStream(), однако, похоже, что FileChannel поддерживает состояние InputStream.

+1

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

+0

Каждый поток должен читать весь файл. – bob

+0

Система имеет 8 гб памяти, и я бы не прочь выделить массив 1 ГБ. Но JVM просто не похоже на это - он использует 100% процессор, пытаясь выделить массив в течение очень долгого времени. – bob

ответ

10

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

Вам действительно нужно 32 потока? Предположительно, у вас не так много ядер, поэтому используйте меньшее количество потоков, и вы получите меньше переключений контекста и т. Д.

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

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

+0

@jon, можно ли использовать инструменты nio для сопоставления структуры Java с файлом на диске, поэтому все, что вам нужно, это написать структуру java и позволить JVM/OS выяснить, как обрабатывать фактические данные чтения ? –

+1

@Thorbjorn: Ну, Java поддерживает файлы с отображением памяти, но если у вас есть больше информации, чем ОС, о том, как вы собираетесь использовать этот файл, вы, возможно, сможете сделать лучше. –

1

Несколько идей:

  1. Написать собственную реализацию InputStream, который действует как вид на FileChannel. Напишите это так, чтобы он не полагался на какое-либо состояние в FileChannel. (т. е. каждый экземпляр должен отслеживать свою собственную позицию, и чтение должно использовать абсолютные чтения в базовом FileChannel.) Это, по крайней мере, помогает вам решить проблемы с каналами.newInputStream(), но это может не решить ваши проблемы со стороны IO ,

  2. Напишите пользовательскую реализацию InputStream, которая действует как представление на MappedByteBuffer. Картирование памяти не должно быть таким же плохим, как на самом деле чтение всего этого в память сразу, но вы все равно будете есть 1 ГБ виртуального адресного пространства.

  3. То же, что и # 1, но с каким-то общим уровнем кеширования. Я бы не пробовал этого, если 1 не окажется достаточно эффективным и 2 не выполним. На самом деле ОС уже должна делать некоторое кэширование для вас в # 1, поэтому здесь вы, по сути, стараетесь быть умнее, чем кэширование файловой системы ОС.

5

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

0

Это очень большой файл. Можете ли вы достать файл как меньший набор файлов? Просто доставка этого файла будет большой работой даже в корпоративной сети.

Иногда легче изменить процесс, чем программу.

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

Смежные вопросы