Какое оптимальное количество потоков для выполнения операций ввода-вывода в java?
В Goetz "Java Concurrency in Practice" в сноске на стр. 101 он пишет: "Для таких вычислительных проблем, которые не используют I/O и не имеют доступа к общим данным, нити Ncpu или Ncpu + 1 обеспечивают оптимальную пропускную способность, больше потоков не помогает, и может фактически ухудшить производительность..."
Мой вопрос заключается в том, что при выполнении операций ввода-вывода, таких как запись файлов, чтение файлов, удаление файлов и т.д., существуют ли рекомендации по количеству потоков для достижения максимальной производительности? Я понимаю, что это будет всего лишь путеводный номер, поскольку в этом участвуют скорости диска и множество других факторов.
Тем не менее, мне интересно: может ли 20 потоков записывать 1000 отдельных файлов на диск быстрее, чем 4 потока на 4-процессорном компьютере?
Ответы
Ответ 1
На практике приложения, связанные с I/O-привязкой, по-прежнему могут существенно выиграть от многопоточности, потому что гораздо быстрее читать или записывать несколько файлов параллельно, чем последовательно. Это особенно характерно, когда общая пропускная способность скомпрометирована за счет латентности сети. Но это также случай, когда один поток может обрабатывать последнее, что он читает, пока другой поток занят чтением, что позволяет повысить загрузку процессора.
Мы можем говорить теорию весь день, но правильный ответ - сделать число потоков настраиваемым. Я думаю, вы обнаружите, что увеличение его за 1 будет увеличивать вашу скорость, но также наступит точка уменьшения прибыли.
Ответ 2
Как и все связанные с производительностью вещи, это зависит.
Если вы привязаны к вводу/выводу, то добавление потоков не поможет вам вообще. (Хорошо, как Стивен Судит указывает, что вы можете увеличить производительность, но это будет небольшим)
Если вы не привязаны к вводу/выводу, добавление потоков может помочь
Не пытайтесь быть умным, но лучший способ узнать это - профилировать его и посмотреть, что работает для ваших конкретных обстоятельств.
Изменить: обновлено на основе комментариев
Ответ 3
Да, 20 потоков могут определенно записать на диск быстрее, чем 4 потока на 4-процессорной машине. Многие реальные программы связаны с вводом-выводом больше, чем с привязкой к ЦП. Тем не менее, это очень подробно зависит от ваших дисков и того, как процессор работает над вашими другими потоками, прежде чем они тоже ожидают этих дисков.
Если все ваши потоки только записываются на диск и ничего не делают, то вполне возможно, что 1 поток на 4-процессорной машине - это самый быстрый способ записи на диск. Все зависит от того, сколько у вас дисков, сколько данных вы пишете и насколько хороша ваша ОС при планировании ввода-вывода. Ваш конкретный вопрос предполагает, что вы хотите, чтобы все 4 письма записывались в один и тот же файл. Это не имеет большого смысла, и в любом практическом сценарии я не могу думать, как это будет быстрее. (Вам нужно будет выделить файл раньше времени, тогда каждый поток будет искать() в другую позицию, и вы в конечном итоге просто изматываете запись, поскольку каждый поток пытается записать несколько блоков.)
Преимущество многопоточности намного проще, когда вы привязаны к сети. Т.е.: ожидание на сервере базы данных или в веб-браузере или тому подобное. Там вы ожидаете нескольких внешних ресурсов.
Ответ 4
См. также Будет ли использовать несколько потоков с производительностью выполнения RandomAccessFile?
UPDATE:
Я добавил там тест.
Ответ 5
Если вы используете синхронный ввод-вывод, у вас должен быть один поток для каждого одновременного запроса ввода-вывода, который может обрабатывать ваш компьютер. В случае одного единственного жесткого диска шпинделя, 1 (вы можете читать или писать, но не одновременно одновременно). Для диска, который может обрабатывать многие запросы ввода-вывода одновременно, это будет, однако, множество запросов, которые он может обрабатывать одновременно.
Другими словами, это не ограничено подсчетом процессора, так как I/O на самом деле не поражает процессор за пределами отправки запросов и ожидания. Подробнее см. здесь.
Там может быть еще одна червь червей с количеством запросов ввода-вывода, которые вы должны иметь в полете в любой момент времени.
Ответ 6
Ncpu + ожидаемое количество параллельных операций ввода-вывода - это мое обычное число.
Ключ не в том, что 20 потоков могут записать один файл на диск быстрее, чем 4 потока. Если у вас всего 1 поток на процессор, то при записи на диск ваш процесс не сможет использовать процессор, на котором размещается поток, который выполняет файл IO. Этот процессор действительно ждет записи файла, тогда как если у вас есть еще один поток, он может использовать CPU для выполнения реальной обработки в промежуточный период.
Ответ 7
Если единственное, что вы делаете с этими потоками, записываете на диск, то увеличение производительности будет незначительным или даже вредным, поскольку обычно драйверы оптимизированы для последовательного чтения на жестких дисках, чтобы вы преобразовывали последовательную запись в файл на несколько "случайных" записей.
Многопоточность может помочь вам при проблемах с привязкой к вводу/выводу, если операции ввода-вывода выполняются на разных дисках, разных сетевых картах или разных серверах баз данных в условиях производительности. Тем не менее с точки зрения наблюдаемой производительности разница может быть намного больше.
Например, представьте, что вы отправляете несколько файлов на множество разных приемников через сеть. Вы по-прежнему привязаны к сети, чтобы ваша максимальная скорость не была выше, чем 100Mb/S, но если вы используете 20 потоков, процесс будет гораздо более справедливым.