C: каждый дочерний процесс читает чередующиеся строки - PullRequest
2 голосов
/ 12 октября 2010

Я обучаю типичной архитектуре сокращения карт (в классах O.S.), и я свободен решать, как главный процесс скажет своим N дочерним процессам проанализировать журнал. Итак, я застрял в этих двух возможностях:

  1. подсчитать количество строк и дать X строк для каждой карты ИЛИ

  2. каждая карта читает строку своего ID и следующую строку для чтения = current_one + number_of_existent_maps Например: с 3 картами каждая прочитает следующие строки:

    • Карта 1: 1, 4, 7, 10, 13
    • Карта 2: 2, 5, 8, 11, 14
    • Карта 3: 3, 6, 9, 12, 15

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

Какой из них вы считаете лучшим? Как я могу сделать scanf или fgets для адаптации к 1) или 2)?

Я был бы рад с примером кода для 2), потому что вилка / трубы не моя проблема: P

RE-EDIT: Мне не рекомендуется использовать выбор здесь, только между процессами карты и процессом сокращения, который будет контролировать чтения. У меня есть ограничения и:

Я хочу, чтобы каждый процесс читал total_lines / N строк. Но, похоже, мне нужно заставить картографический процесс открыть файл и затем прочитать соответствующие строки. Итак, вот мои сомнения:

1- Это плохо или вообще возможно, чтобы все проки открывали файл одновременно или почти одновременно? Как это поможет в ускорении?

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

Как правильно разделить количество строк на N карт и поместить их для чтения одновременно? Я думаю, что fseek () может быть хорошим оружием, но я не знаю, КАК я могу его использовать. Помогите, пожалуйста!

Ответы [ 3 ]

6 голосов
/ 12 октября 2010

Если я правильно понял, вы хотите, чтобы все процессы читали строки из одного файла.Я не рекомендую это, это немного грязно, и вам придется а) читать одни и те же части файла несколько раз или б) использовать блокировку / мьютекс или какой-то другой механизм, чтобы избежать этого.Это будет сложно и сложно отлаживать.

Я бы попросил главный процесс прочитать файл и назначить строки для пула подпроцессов.Вы можете использовать общую память, чтобы ускорить это и уменьшить потребность в копировании данных IPC;или используйте потоки.

Что касается примеров, я ответил на вопрос о разветвлении и IPC и дал фрагмент кода для примера функции, которая разветвляется и возвращает пару каналов для связи родитель-потомок.Позвольте мне посмотреть, что (...) здесь это = P Может ли popen () создавать двунаправленные трубы, такие как pipe () + fork ()?

edit Я продолжал думать об этом = P.Вот идея:

  • Иметь подпроцессы вызова основного процесса с чем-то похожим на то, что я показал в ссылке выше.

  • Каждый процесс начинается сотправка байта мастеру для оповещения о готовности и блокировка на read().

  • Пусть основной процесс прочитает строку из файла в буфер общей памяти и заблокируетselect() на его дочерних каналах.

  • Когда select() вернется, прочитайте один из байтов, сигнализирующих о готовности, и отправьте этому подпроцессу смещение строки в пространстве общей памяти.

  • Основной процесс повторяется (читает строку, блокирует при выборе, читает байт для использования события готовности и т. Д.)

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

(Вы можете избежать буфера общей памяти, если хотите, и отправитьлинии вниз по трубам, хотя это будет включать в себя постоянную dата-копирования.Если обработка каждой строки является вычислительно дорогой, это не будет иметь большого значения;но если строки требуют небольшой обработки, это может замедлить вас.)

Надеюсь, это поможет!

изменить 2 на основе комментариев Ньюбы:

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

Итак, главный процесс:

  • Создает подпроцессы, используя что-то вроде функции, которую я написал (ссылка выше), которая создает каналы для двунаправленной связи.

  • Чтениестрока из файла в буфер (частная, локальная, без общей памяти).

  • Теперь у вас есть данные, готовые для обработки.Вызовите select (), чтобы заблокировать все каналы, которые связывают вас с вашими подпроцессами.

  • Выберите любой из каналов, для которых имеются данные, прочитайте из него один байт и затем отправьте строкуВы ожидаете обработки в буфере вниз по соответствующему каналу (помните, у нас было по 2 на дочерний процесс, чтобы идти вверх, один - вниз).

  • Повторите с шага 2то есть прочитайте еще одну строку.

Дочерние процессы:

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

  • Блокировать на read(), ожидая, пока ведущий процесс (который знает, что вы готовы после шага 1) отправит вам данные для обработки.Продолжайте читать, пока не достигнете новой строки (вы сказали, что читали строки, верно?).Примечание. Я следую вашей модели, отправляя по одной строке каждому процессу за раз, вы можете отправить несколько строк, если хотите.

  • Обработка данных.

  • Вернитесь к шагу 1, то есть отправьте еще один байт, чтобы указать, что вы готовы к дополнительным данным.

Итак, простой протокол для назначения задач такому числу подпроцессов, какты хочешь.Может быть интересно запустить тест с 1 ребенком, n детьми (где n - количество ядер на вашем компьютере) и более чем с n детьми, и сравнить результаты.

Вот так, это был длинный ответ.Я очень надеюсь, что помог xD

0 голосов
/ 12 октября 2010

Использовать шаблон очереди мастера и подчиненного устройства.

  • Мастер устанавливает подчиненных, которые сидят в очереди в ожидании рабочих элементов.
  • Затем мастер читает строку за строкой.
    • Каждая строка затем представляет рабочий элемент, который вы помещаете в очередь
      с указателем функции того, как это работает.
    • Один из ожидающих подчиненныхполучает элемент из очереди
    • Подчиненный обрабатывает рабочий элемент.
    • Когда ведомый завершает работу, он возвращается в рабочую очередь.
0 голосов
/ 12 октября 2010

Поскольку каждый из процессов должен будет прочитать файл целиком (если только строки журнала не имеют одинаковую длину, что необычно), ваше предложение на самом деле не принесет пользы 2.

Если вы собираетесь разделить работу на 3, я бы сделал:

  • Измерьте (stat ()) размер файла журнала - назовите его N байтов.
  • Выделите диапазон байтов 0 .. (N / 3) первому дочернему элементу.
  • Выделите диапазон байтов (N / 3) + 1..2 (N / 3) второмуchild.
  • Выделите диапазон байтов 2 (N / 3) + 1..end третьему дочернему элементу.
  • Определите, что второй и третий дочерние элементы должны синхронизироваться, читая вперед до первогоразрыв строки после их начальной позиции.
  • Определите, что каждый дочерний элемент отвечает за чтение до первого разрыва строки в конце или после конца их диапазона.
  • Обратите внимание, что третий дочерний элемент (последний дочерний элемент)возможно, придется делать больше работы, если файл журнала растет.

Тогда процессы читают независимоnt сегментов файла.

(Конечно, когда все они совместно используют файл, пул системных буферов сохраняет перечитываемые данные на диске, но данные по-прежнему копируются в каждый из трех процессов, только для каждого из них.процесс выбрасывает 2/3 того, что было скопировано как чужое задание.)


Еще один, более радикальный вариант:

  • mmap () файла журнала в память.
  • Назначьте дочерние элементы различным сегментам файла в соответствии с описанными ранее линиями.

Если вы работаете на 64-битной машине, это работает довольно хорошо.Если ваши файлы журнала не слишком массивны (скажем, 1 ГБ или меньше), вы можете сделать это и на 32-битной машине.Когда размер файла становится больше 1 ГБ или около того, вы можете начать сталкиваться с проблемами отображения и выделения памяти, хотя вам вполне может обойтись до тех пор, пока вы не достигнете размера чуть менее 4 ГБ (на 32-разрядной машине).Другая проблема здесь связана с растущими файлами журналов.AFAIK, mmap () не отображает дополнительную память, поскольку в файл записываются дополнительные данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...