Тестовое задание

Тема в разделе "WASM.HEAP", создана пользователем Portman, 7 апр 2011.

  1. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    Недавно связывался с компанией XYZ, хотел на работу устроиться. Выслали тестовое задание. Кратко, суть в следующем: написать многопоточную программу для сжатия файлов в формат gzip. На вход поступает имя исходного и результирующего файла. Программа должна работать, используя все доступные процессоры и уметь обрабатывать файлы, размер которых превышает объем доступной оперативной памяти.

    Задание само по себе не очень сложное. Я написал программу, которая сжимает файл блоками параллельно в нескольких потоках. Алгоритм следующий:
    1. Вычисляются границы блоков (начало, длина)
    2. Раздаются задания потокам: каждый поток сжимает свой блок и записывает во временный файл
    3. Основной поток ждет завершения всех рабочих потоков
    4. Полученные файлы объединяются

    Выслал. Пришел следующий ответ: программа работает хорошо, но только медленно. Ускорьте в 4 (четыре) раза, тогда поговорим.

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

    Подумал немного, почитал доки. Решил что дело в одновременном чтении-записи нескольких файлов из нескольких потоков. Платформа - Виндовс. Провел эксперименты с параллельным и последовательным чтением-записью, с размерами буферов. В итоге более чем на 25% увеличить производительность не получилось.

    Пришел к выводу что ускорить программу в 4 раза невозможно теоретически.

    В чем подвох?

    Забыл добавить: алгоритм сжатия по условиям задания библиотечный, т.е. самому его писать не надо было.
     
  2. artkar

    artkar New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2005
    Сообщения:
    400
    Адрес:
    Russia
    А Чё алгоритм gzip поддаётся распаралеливанию?
    Можно вкратце его суть ? Это одна из модификаций Лемпеля-Зива?
     
  3. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А зачем во временный файл? MMap не лучше?
     
  4. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    Да, Лемпель-Зив. Но сам алгоритм не поддается распараллеливанию - он по существу последовательный. Здесь помогает та его особенность, что если исходный файл распилить на куски, куски сжать по отдельности, а потом склеить в таком же порядке, то получится вполне корректный zip-архив, который открывается, например WinRar-ом.
     
  5. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    Booster
    Дело в том, что до завершения сжатия фрагмента неизвестна его длина в сжатом состоянии.
     
  6. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Portman
    Максимально возможный размер. Но вряд ли это даст 4x.
     
  7. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    ну ёлки-палки, производительность программы в первую очередь можно завалить непотребным обращением к фс.
    может, это и в конце, может и занимает на хорошем железе пару секунд, но некрасиво, особенно в качестве показательной работы.
     
  8. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Portman
    Это интересно. Если можно, выложите исходники (вместе с библиотекой сжатия). Может всё-таки удастся увидеть какие-то возможности...
     
  9. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    Программа написана на C#. Библиотека сжатия - это System.IO.Compression.GzipStream.
     
  10. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    А факт того, что программе может быть дано сразу несколько файлов на сжатие, учли?

    UPD. Все new byte[] повыносить из циклов. Создать единожды при старте.
    UPD2. Поиграться с размерами буферов.
    UPD3. А почему склейка в один поток?
     
  11. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Portman
    Это было условием тестового задания?
     
  12. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    SadKo
    По условиям задания входной файл один.

    Насчет byte[] верно, упустил. С буферами играл, до 10Мб дает небольшое увеличение, потом не влияет. А есть смысл склейку распараллеливать - диск-то все равно один?

    green
    Да.
     
  13. artkar

    artkar New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2005
    Сообщения:
    400
    Адрес:
    Russia
    Ну если так можно, то распаралеливается.... (а ведь и впрям можно)
    Разве нельзя писать в поток сразу (не создавая временные файлы)?? Покопай вроде у .НЕТ в ФайлСтрим можно?
     
  14. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    Portman
    > 3. Основной поток ждет завершения всех рабочих потоков
    зачем? тут не нужен основной поток. зачем ему ждать? пусть тоже работает.

    > 4. Полученные файлы объединяются
    тут сильная просадка производительности, очевидно. двойная запись на диск. а зачем?

    > Ускорьте в 4 (четыре) раза, тогда поговорим.
    вероятно, они сравнивали скорость с эталоном (программой, которую написали сами). отсюда и 4 раза. хотя, может, и с потолка цифру взяли.

    > Такой ответ меня удивил, поскольку при тестировании программа
    > показала 100% загрузку всех процессоров практически на всем протяжении работы.
    это ни о чем не говорит.

    > Решил что дело в одновременном чтении-записи нескольких файлов из нескольких потоков.
    это действительно узкое место.

    > Пришел к выводу что ускорить программу в 4 раза невозможно теоретически.
    возьмите архиватор с поддержкой многопоточности и посмотрите сколько он будет сживать тот же самый файл. обычно, готовые программы неплохо оптимизированы и вполне могут быть эталоном.

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

    ntkernelspawn New Member

    Публикаций:
    0
    Регистрация:
    17 дек 2010
    Сообщения:
    61
    Portman
    - Вы в корне не правильно распаралелили задачи ... Вам требует главный поток и еще один для записи на диск.
    Программный код написан плохо. Сихшный подход, генерация исключений без их обработки.
     
  16. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Portman
    Думаю, следует уменьшить размер сжимаемого блока, отвяжите размер блока от количества рабочих потоков - пусть он ограничивается снизу только из соображений эффективности и качества сжатия. Далее, не привязывайте каждый поток к фиксированному смещению (смещениям), пусть получает просто следующий блок из файла.
    Во-первых, это увеличит локальность чтения входного файла, а во-вторых - позволит обойтись без промежуточных файлов (т.е. можно будет писать в MemoryStream).

    Кстати, один из потоков может писать сразу в выходной файл.
     
  17. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    green
    А ведь точно! Сжимать небольшими блоками, тогда можно будет писать сразу в выходной файл, когда очередная порция блоков будет сжата. Надо попробовать...
     
  18. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    ntkernelspawn
    Я никогда не понимал, зачем нужен главный поток. Главный поток -- как и любое начальство: делать ничего не делает, только никому ненужные указания раздаёт, а ресурсы потребляет.
    Portman
    Не надо временных файлов. Это лишние копирования данных. Как минимум копирования вида RAM->RAM, как максимум RAM->HDD и, даже, HDD->RAM. Копирование с/на HDD будет влиять на производительность, лишь если программа выбирает всю скорость жёстких дисков. Но даже копирования RAM->RAM -- это ужос.
    Прежде чем писать алгоритмы компрессии, надо написать две функции, первая для получения следующего блока для сжатия, вторая для отправления сжатого блока на вывод. Первая пишется тривиально, вторая чуть хитрее, она должна переупорядочивать сжатые блоки, располагать их по-порядку, и, по-мере возможности, писать на диск. Причём либо писать асинхронно, либо, как тут советовали, придётся заводить отдельный поток для записи на диск. Ещё один поток -- по-моему, правильнее, ведь его можно заодно озадачить вопросами чтения исходного файла, чтобы рабочие треды не связывались бы с вводом/выводом, сделать эдакий prefetch блоков в адресное пространство процесса: если сжатие происходит быстрее чтения, то это позволит выжать максимум из жёсткого диска.
    kaspersky
    Что в нём узкого? Эти несколько файлов, по-идее должны находиться в дисковом кеше и не должно возникать необходимости трясти головками жёсткого диска. Эти файлы будут читаться из RAM, которая по-определению рандом-акцесс, и ей плевать в каком порядке будут читаться данные. Проблема не в том, что их несколько и io происходит одновременно, проблема в том, что этот io вообще есть.
    Хотя, с другой стороны, если сжимать гигабайт несколько, то да, эти файлы начнут пропадать из дискового кеша, и тогда будут уже серьёзные тормоза.
     
  19. Portman

    Portman New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2008
    Сообщения:
    49
    r90
    Ну, это действительно может быть узким местом. Особенно при чтении, если верить вот этой статье http://www.ixbt.com/storage/wd4000ncq.shtml. Особенно интересна третья диаграмма сверху . Согласно ей, при многопоточном чтении из далеко отстоящих областей диска скорость получения данных может падать на порядок.
     
  20. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    Portman
    И где системное мышление? В статье идёт речь о чтении именно с жёсткого диска. Ты же читаешь файлы, которые только что записал. Эти файлы кешируются в RAM ядром. И их чтение не порождает никакого общения с жёстким диском.
    Это действительно может быть узким местом: