2016-08-04 7 views
2

Есть ли удобный способ получить статус «map»/pmap в Julia?Julia - статус функции карты

Если бы я был массив а = [1:10] я хотел бы либо:

1: перечислить массив и использовать, если условный добавить команду печати

((index,value) -> 5*value ......, enumerate(a) 

и где «.......», там будет способ „цепочки“ анонимной функции к чему-то вроде

"5*value and then print index/length(a) if index%200 == 0" 

2: знать, если есть уже существующий вариант для этого, как ртар предназначен для параллельных задач, которые обычно используется для больших процессов, поэтому для этого уже существовало бы существование?

Кроме того, существует ли способ сделать анонимные функции двумя «отдельными» вещами один за другим?

Пример

, если у меня есть

a = [1:1000] 
function f(n) #something that takes a huge ammount of time 
end 

и я исполню

map(x -> f(x), a) 

РЕПЛ будет распечатать статус

"0.1 completed" 
. 
. 
. 
"0.9 completed" 

Решение

Chris Rackauckas answer

битенг странно, что пакет ProgressMeter не включает это по умолчанию

Pkg.add("ProgressMeter") 
Pkg.clone("https://github.com/slundberg/PmapProgressMeter.jl") 
@everywhere using ProgressMeter 
@everywhere using PmapProgressmeter 
pmap(x->begin sleep(1); x end, Progress(10), 1:10) 

PmapProgressMeter на GitHub

+0

Непонятно, что вы подразумеваете под статусом. Приведите пример вывода, который вы хотите использовать для конкретного входного вектора. –

+0

«статус» как в том, как далеко за счет оценки я отправил пример, чтобы уточнить – isebarn

ответ

3

ProgressMeter.jl имеет ветвь для pmap.

Вы также можете сделать индикатор выполнения Juno внутри pmap. Это своего рода использование недокументированных вещей, поэтому вы должны спросить у Gitter, если вам нужна дополнительная информация, потому что публикация этой публикации просто смущает людей, если/когда она изменится.

+0

хороший улов вероятной проблемы [XY Problem] (http://xyproblem.info): p –

+0

Отлично! Спасибо. – isebarn

1

Почему бы не просто включить его в определении вашей функции к печати эта информация? Например.

function f(n) #something that takes a huge amount of time 
    ... 
    do stuff. 
    ... 
    println("completed $n") 
end 

И, вы можете добавить дополнительный аргумент в вашу функцию, при желании, которая содержала бы, что 0.1 ..., 0.9 в вашем примере (который я не совсем уверен, что те, но все они есть, они могут просто быть аргументом в вашей функции).

Если вы посмотрите на приведенный ниже пример на pmap и @parallel, вы найдете пример функции, переданной в pmap, которая выводит результат.

Смотрите также this и this SO разместить на информацию для подачи нескольких аргументов для функций, используемых с map и pmap.



Джулия documentation советует

ртар() предназначен для случая, когда каждый вызов функции делает большой объем работы. Напротив, @parallel for может обрабатывать ситуации, когда каждая итерация крошечная, возможно, просто суммируя два числа.

Для этого есть несколько причин. Во-первых, pmap берет на себя большие затраты на запуск рабочих мест. Таким образом, если задания очень малы, эти затраты на запуск могут стать неэффективными. Напротив, однако, pmap выполняет «умную» работу по распределению рабочих мест среди работников. В частности, он создает очередь заданий и отправляет новое задание каждому работнику всякий раз, когда этот рабочий становится доступным. @parallel, напротив, разворачивает всю работу, выполняемую среди рабочих, когда она называется. Таким образом, если некоторые работники занимают больше времени на своих рабочих местах, чем другие, вы можете столкнуться с ситуацией, когда большинство ваших работников закончили и простаивают, в то время как некоторые из них остаются активными в течение чрезмерного количества времени, заканчивая свою работу. Однако такая ситуация реже встречается с очень маленькими и простыми рабочими местами.

Ниже приведено следующее: предположим, что у нас есть два рабочих, один из которых медленный, а другой из них в два раза быстрее. В идеале мы хотели бы дать быструю рабочую работу в два раза больше работы, чем медленный рабочий. (или мы могли бы иметь быструю и медленную работу, но главное - то же самое). pmap выполнит это, но @parallel не будет.

Для каждого теста мы инициализируем следующее:

addprocs(2) 

@everywhere begin 
    function parallel_func(idx) 
     workernum = myid() - 1 
     sleep(workernum) 
     println("job $idx") 
    end 
end 

Теперь для теста @parallel, мы выполним следующее:

@parallel for idx = 1:12 
    parallel_func(idx) 
end 

И получить обратно вывода на печать:

julia>  From worker 2: job 1 
    From worker 3: job 7 
    From worker 2: job 2 
    From worker 2: job 3 
    From worker 3: job 8 
    From worker 2: job 4 
    From worker 2: job 5 
    From worker 3: job 9 
    From worker 2: job 6 
    From worker 3: job 10 
    From worker 3: job 11 
    From worker 3: job 12 

Это почти сладкое. Рабочие «разделили» работу равномерно. Обратите внимание, что каждый рабочий выполнил 6 заданий, хотя рабочий 2 в два раза быстрее, чем рабочий 3. Он может касаться, но он неэффективен.

Для для испытания pmap, я бегу следующее:

pmap(parallel_func, 1:12) 

и получить на выходе:

From worker 2: job 1 
From worker 3: job 2 
From worker 2: job 3 
From worker 2: job 5 
From worker 3: job 4 
From worker 2: job 6 
From worker 2: job 8 
From worker 3: job 7 
From worker 2: job 9 
From worker 2: job 11 
From worker 3: job 10 
From worker 2: job 12 

Теперь, обратите внимание, что работник 2 выполнил 8 рабочих мест и работник 3 выполнил 4 Это точно пропорционально их скорости и тому, что мы хотим для оптимальной эффективности. pmap - это трудная задача мастера - от каждого в зависимости от их способности.

+0

. Вы правы, это хороший способ решить эту проблему. Я ранее читал (неправильно), что pmap может принимать только функцию и «единственный» вектор в качестве аргумента, который оказался неверным, поэтому проблема более или менее решается таким образом, предоставляя дополнительный вектор «подсчета» для печати из – isebarn

+0

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

+0

Предположим, вы могли бы сделать это функцией с двумя аргументами, а также передать массив «индексов» для отслеживания обработанных элементов ... но опять же, это не было бы надежным для pmap, так как это не гарантировано последовательный. –

1

Вы можете создать функцию с состоянием, как вы просите, путем реализации «закрытия». Например.

julia> F = function() 
    ClosedVar = 5 
    return (x) -> x + ClosedVar 
end; 
julia> f = F(); 
julia> f(5) 
10 
julia> ClosedVar = 1000; 
julia> f(5) 
10 

Как вы можете видеть, функция f поддерживает 'состояние' (т.е.внутренняя переменная ClosedVar является локальной для F, а f поддерживает доступ к ней, хотя F сам по себе технически давно вышел из сферы действия.

Обратите внимание на разницу с нормальным, незамкнутым определением функции:

julia> MyVar = 5; 
julia> g(x) = 5 + MyVar; 
julia> g(5) 
10 
julia> MyVar = 1000; 
julia> g(5) 
1005 

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

Сказав, что из вашего примера вы, кажется, ожидаете, что pmap будет запускаться последовательно. Это не гарантируется. Поэтому не следует полагаться на подход «какой индекс является эта обработка потоков» для печати каждые 200 операций. Вам, вероятно, придется поддерживать закрытую переменную «счетчик» внутри вашего закрытия и полагаться на это. Из чего предположительно также следует, что ваше закрытие должно быть доступно @everywhere

0

Еще одна возможность - использовать SharedArray в качестве счетчика, совместно используемого среди рабочих. Например.

addprocs(2) 

Counter = convert(SharedArray, zeros(Int64, nworkers())) 

## Make sure each worker has the SharedArray declared on it, so that it need not be fed as an explicit argument 
function sendto(p::Int; args...) 
    for (nm, val) in args 
    @spawnat(p, eval(Main, Expr(:(=), nm, val))) 
    end 
end 

for (idx, pid) in enumerate(workers()) 
    sendto(pid, Counter = Counter) 
end 
@everywhere global Counter 


@everywhere begin 
    function do_stuff(n) 
     sleep(rand()) 
     Counter[(myid()-1)] += 1 
     TotalJobs = sum(Counter) 
     println("Jobs Completed = $TotalJobs") 
    end 
end 

pmap(do_stuff, 1:10) 
+0

Я на самом деле пробовал то же самое, но это было немного сложнее, и я хотел получить более простое решение. Тем не менее, я никогда не мог получить работников, которых я назначил типам SharedArray, чтобы фактически иметь доступ к массиву, теперь я вижу, что они должны быть объявлены глобальными. Параллелизм в julia затруднен – isebarn

+0

@isebarn Да, материал параллелизма немного сложнее привыкнуть. Я работаю над созданием на нем документации SO, но есть еще достойный бит, который я еще не получил. На самом деле глобальная декларация не является обязательным условием - вместо этого это операция 'sendto'. Глобальный просто делает аргументы глобальными для каждого работника, так что функция становится легче и быстрее, чтобы знать, где их искать, но она найдет их в конечном итоге даже без этого. –