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

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

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

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

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

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

Некоторые детали:

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

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

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

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

12.08.2008 19:50:13
6 ОТВЕТОВ
РЕШЕНИЕ

Проблема, кажется, в политике планирования ввода-вывода Windows. В соответствии с тем, что я нашел здесь , для ОС существует множество способов планирования запросов к диску. В то время как Linux и другие могут выбирать между различными политиками, до Vista Windows была заблокирована в одной политике: очередь FIFO, где все запросы были разделены на блоки по 64 КБ. Я полагаю, что эта политика является причиной проблемы, с которой вы столкнулись: планировщик будет смешивать запросы из двух потоков, вызывая непрерывный поиск между различными областями диска.
Хорошая новость заключается в том, что в соответствии с этим здесь и здесь Vista представила более интеллектуальный планировщик дисков, в котором вы можете установить приоритет ваших запросов, а также выделить минимальную пропускную способность для вашего процесса.
Плохая новость заключается в том, что я не нашел способа изменить политику дисков или размер буферов в предыдущих версиях Windows. Кроме того, даже если повышение приоритета дискового ввода-вывода вашего процесса повысит производительность по сравнению с другими процессами, у вас по-прежнему будут проблемы, когда ваши потоки конкурируют друг с другом.
Что я могу предложить, так это изменить ваше программное обеспечение, введя собственную политику доступа к диску.
Например, вы можете использовать такую ​​политику в вашей теме B (аналогично для темы 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 также можно автоматически настраивать, проверяя фактические скорости передачи и медленно изменяя их, тем самым максимизируя пропускную способность при работе приложения на разных машинах и / или ОС. Вы можете обнаружить, что уровни кэша, памяти или RAID влияйте на них так или иначе, но с автонастройкой вы всегда получите лучшую производительность в каждом сценарии.

11
13.08.2008 13:47:39

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

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

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

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


Изменить, чтобы добавить некоторые дополнительные детали для Уилла Дина:

Конечно, по этим различным аппаратным конфигурациям исходные цифры менялись (иногда существенно). Проблема, однако, заключается в постоянном снижении производительности, от которого страдает только 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.
  • Мой домашний марочный ПК (AMD Athlon64) под управлением Windows XP (32-разрядная версия), FreeBSD (64-разрядная версия) и Linux (64-разрядная версия) с одним диском.
  • Мой домашний MacBook (Intel Core1) под управлением Mac OS X, один диск SATA.
  • Мой домашний компьютер Koolu под управлением Linux. По сравнению с другими системами он значительно слабее, но я продемонстрировал, что даже эта машина может превзойти сервер Windows с RAID5 при многопоточном чтении с диска.

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

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

5
20.04.2015 08:26:01
Добро пожаловать в Microsoft.
v.oddou 4.08.2015 02:42:00

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

0
12.08.2008 20:04:13

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

Это только «внутреннее чувство», но это заставляет меня сомневаться, что это действительно простая проблема с поиском. Кроме OS X и Raid5, все это пробовали на одной и той же машине - пробовали ли вы другую машину? Ваш процессор в основном равен нулю во время этого теста?

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

1
12.08.2008 20:20:17
для одного привода против raid5: если вы читаете последовательные данные из двух достаточно больших файлов, вы не можете избежать всех дисковых головок, ищущих вперед и назад; размер полосы обычно составляет 16-128 кБ, поэтому для считывания 1 МБ данных вам понадобятся все (или большинство) головок, чтобы искать их там.
tzot 10.10.2008 11:23:38

Используете ли вы IOCompletionPorts под Windows? В Windows через C ++ есть глубокая глава на эту тему, и, как повезет, она также доступна на MSDN .

0
12.08.2008 21:38:05

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

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

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

0
13.08.2008 09:44:26
если я займусь этим, просто чтобы заставить что-то работать на windows, я бы просто предложил перенести его процесс на linux. Какова стоимость каждого решения? честно ...
v.oddou 4.08.2015 02:43:59