Подтвердить что ты не робот

Как получить хорошую одновременную производительность чтения с диска

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

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

Наш опыт работы с этой установкой в ​​Windows очень низок. Суммарная пропускная способность двух потоков составляет порядка 2-3 Мбайт/сек. Похоже, что диск тратит большую часть своего времени на поиск назад и вперед между двумя файлами, по-видимому, очень мало читайте после каждого поиска.

Если мы отключим один из потоков и временно посмотрим на производительность одного потока, мы получим намного лучшую пропускную способность (~ 45 Мбайт/сек для этой машины). Таким образом, плохая двухпоточная производительность является артефактом планировщика дисков ОС.

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

Некоторые сведения:

Файлы стоят порядка 2 гигабайт каждый на машине с 2 Гбайт ОЗУ. Для целей этого вопроса мы считаем, что они не должны быть кэшированы и отлично дефрагментированы. Мы использовали инструменты дефрагментации и перезагрузились, чтобы убедиться в этом.

Мы не используем специальные API для чтения этих файлов. Поведение повторяется в различных API-интерфейсах, таких как Win32 CreateFile, C fopen, С++ std:: ifstream, Java FileInputStream и т.д.

Каждый поток вращается в цикле, вызывая вызовы функции чтения. Мы изменили количество байтов, запрошенных у API, каждую итерацию от значений между 1KiB и 128MiB. Из-за этого это не имело никакого эффекта, поэтому ясно, что количество физически считываемых ОС после каждого поиска диска не продиктовано этим числом. Это именно то, что следует ожидать.

Резкое различие между однопоточными и двухпоточными характеристиками повторяется в Windows 2000, Windows XP (32-разрядная и 64-разрядная), Windows Server 2003, а также с аппаратным RAID5 и без него.

4b9b3361

Ответ 1

Проблема, похоже, связана с политикой планирования ввода-вывода Windows. Согласно тому, что я нашел здесь, существует много способов для O.S. для планирования запросов на диск. Хотя Linux и другие могут выбирать между различными политиками, до того, как Vista Windows была заблокирована в одной политике: очередь FIFO, где все запросы, разделенные блоками в 64 КБ. Я считаю, что эта политика является причиной проблемы, с которой вы сталкиваетесь: планировщик будет смешивать запросы из двух потоков, вызывая непрерывный поиск между различными областями диска.
Хорошая новость заключается в том, что согласно здесь и здесь, Vista представила более гибкий планировщик дисков, в котором вы можете установить приоритет своих запросов, а также выделить минимальную пропускную способность для ваш процесс.
Плохая новость заключается в том, что я не нашел способа изменить размер политики диска или буфера в предыдущих версиях Windows. Кроме того, даже если повышение приоритета ввода-вывода на диске вашего процесса повысит производительность по сравнению с другими процессами, у вас все еще есть проблемы с вашими нитями, конкурирующими друг с другом.
Я могу предложить вам изменить ваше программное обеспечение, внедрив политику самостоятельного доступа к диску.
Например, вы можете использовать такую ​​политику в своем потоке B (аналогично для Thread A):

if THREAD A is reading from disk then wait for THREAD A to stop reading or wait for X ms
Read for X ms (or Y MB)
Stop reading and check status of thread A again  

Вы можете использовать семафоры для проверки статуса, или вы можете использовать счетчики perfmon, чтобы получить статус реальной очереди диска. Значения X и/или Y также могут быть автоматически настроены путем проверки фактических скоростей передачи и медленного изменения их, таким образом максимизируя пропускную способность, когда приложение работает на разных машинах и/или O.S. Вы можете обнаружить, что уровни кеша, памяти или RAID влияют на них так или иначе, но с автоматической настройкой вы всегда получите максимальную производительность в каждом сценарии.

Ответ 2

Я хотел бы добавить некоторые примечания в свой ответ. Все остальные операционные системы, отличные от Microsoft, которые мы тестировали, не страдают от этой проблемы. Linux, FreeBSD и Mac OS X (этот последний на разных аппаратных средствах) все более грациозно снижаются с точки зрения совокупной пропускной способности при переходе от одного потока к другому. Linux, например, деградировал от ~ 45 Мбайт/сек до ~ 42 Мбайт/сек. Эти другие операционные системы должны считывать большие куски файла между каждым поиском и не тратить почти все свое время на поиск диска.

Наше решение для Windows - передать флаг FILE_FLAG_NO_BUFFERING в CreateFile и использовать большие (~ 16MiB) чтения в каждом вызове ReadFile. Это неоптимально по нескольким причинам:

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

(Как последнее замечание. Объясняет ли это, почему замена под Windows настолько адская? То есть, Windows неспособна выполнять IO к нескольким файлам одновременно с любой эффективностью, поэтому при замене всех других операций ввода-вывода приходится непропорционально медленно. )


Изменить, чтобы добавить дополнительные сведения о Will Dean:

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

  • Несколько рабочих станций Dell (Intel Xeon) разных возрастов под управлением Windows 2000, Windows XP (32-разрядная версия) и Windows XP (64-разрядная версия) с одним диском.
  • Сервер Dell 1U (Intel Xeon) под управлением Windows Server 2003 (64-разрядный) с RAID 1 + 0.
  • Рабочая станция HP (AMD Opteron) с Windows XP (64-разрядная версия) и Windows Server 2003 и аппаратный RAID 5.
  • Мой домашний unbranded ПК (AMD Athlon64), работающий под управлением Windows XP (32-разрядный), FreeBSD (64-разрядный) и Linux (64-разрядный) с одним диском.
  • Мой домашний MacBook (Intel Core1) работает под управлением Mac OS X, одного диска SATA.
  • Мой дом Koolu ПК под управлением Linux. Сильно недоукомплектованный по сравнению с другими системами, но я продемонстрировал, что даже эта машина может превосходить сервер Windows с RAID5 при чтении многопоточных дисков.

Использование ЦП во всех этих системах было очень низким во время тестов, и антивирус был отключен.

Я забыл упомянуть об этом, но мы также попробовали обычный API Win32 CreateFile с установленным флагом FILE_FLAG_SEQUENTIAL_SCAN. Этот флаг не устранил проблему.

Ответ 3

Кажется немного странным, что вы не видите разницы в довольно широком диапазоне версий Windows и ничего между одним приводом и аппаратным RAID-5.

Это только "кишка чувствует", но это делает меня сомнительным, что это действительно простая проблема поиска. Помимо OS X и Raid5, все это было проверено на одной машине - вы пробовали другую машину? Является ли ваше использование ЦП в целом нулевым во время этого теста?

Какое самое короткое приложение вы можете написать, которое демонстрирует эту проблему? - Мне было бы интересно попробовать его здесь.

Ответ 4

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

Ответ 6

Пол - увидел обновление. Очень интересно.

Было бы интересно попробовать это на Vista или Win2008, так как люди, кажется, сообщают о некоторых значительных улучшениях ввода-вывода на них в некоторых обстоятельствах.

Мое единственное предложение о другом API было бы попытаться сопоставить память с файлами - вы пробовали это? К сожалению, на 2 ГБ на файл вы не сможете сопоставить несколько целых файлов на 32-битной машине, что означает, что это не так уж и тривиально, как могло бы быть.