Как вы регулируете параллелизм / относительную производительность процесса в Erlang? - PullRequest
3 голосов
/ 07 июня 2011

Допустим, мне нужно прочитать из каталога, в котором много больших XML-файлов, и мне нужно проанализировать его и отправить по сети в какой-то сервис, а затем снова записать ответ на диск.

Если бы это был Java или C ++ и т. Д., Я мог бы сделать что-то вроде этого (надеюсь, это имеет смысл):

(File read & xml parsing process) -> bounded-queue -> (sender process) -> service

service -> bounded-queue -> (process to parse result and write to disk)

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

Что я должен делать при кодировании в Erlang?Думаю, я мог бы просто реализовать весь поток в функции, затем выполнить итерацию в каталоге и порождать эти процессы от начала до конца как можно быстрее.Это звучит неоптимально, хотя, если анализ XML занимает больше времени, чем чтение файлов и т. Д. Приложения.может привести к нехватке памяти из-за одновременного хранения большого количества документов XML в памяти и т. д., и вы не сможете поддерживать параллелизм на оптимальном уровне.Например, если «сервис» наиболее эффективен, когда параллелизм равен 4, было бы очень неэффективно поражать его огромным параллелизмом.

Как программистам на эрланге приходится иметь дело с такой ситуацией?Т.е. что является заменой erlang для фиксированного пула потоков и ограниченной очереди?

Ответы [ 3 ]

3 голосов
/ 07 июня 2011

Вы, безусловно, можете запустить свой собственный пул процессов в Erlang, но это плохой способ использования памяти, поскольку он не учитывает размер читаемых данных XML (или общий объем памяти, используемый процессами в этом отношении.).

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

2 голосов
/ 07 июня 2011

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

Также возможно ограничение количества порождаемых процессов. Простая конструкция будет:

pool(Max) -> 
    process_flag(trap_exit, true),
    pool(0, Max);
pool(Current, Max) ->
    receive
        {'EXIT', _, _} -> 
            pool(Current - 1, Max);
        { work, F, Pid} when Current < Max -> 
            Pid ! accepted,
            spawn_link(F),
            pool(Current + 1, Max);
        { work, _, Pid} -> 
            Pid ! rejected,
            pool(Current, Max);
    end.

Это грубый набросок того, как процесс будет ограничивать количество процессов, которые он порождает. Однако считается, что лучше ограничивать реальные причины, а не искусственные числа.

1 голос
/ 07 июня 2011

Я бы посоветовал вам сделать это в управляемой событиями парадигме.

Представьте, что вы запустили OTP gen_server со списком имен файлов.

  1. gen_servers проверяет ресурсы и порождает следующего работника, если это разрешено, удаляя имя файла из списка и передавая его работнику.

  2. Рабочий обрабатывает файл и возвращает сообщение обратно в gen_server, когда он готов (или вы можете просто перехватить EXIT).

  3. gen_server получает такое сообщение и выполняет шаг 1, пока список файлов не станет пустым.

Так что рабочие выполняют тяжелую работу, gen_server контролирует поток.

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

Рабочие могут быть дополнительно разделены, если вам нужно больше параллелизма.

...