Giter Club home page Giter Club logo

paralleloperations.jl's Introduction

ParallelOperations.jl

Basic parallel algorithms for Julia

codecov

Features:

  • User-friendly interface
  • 100% auto-test coverage
  • All of the operations could be executed on specified Modules
  • Commonly used operations
  • Send function methods to remote at runtime

Install

]add ParallelOperations

or

]add https://github.com/JuliaAstroSim/ParallelOperations.jl

Usage

using Test
using Distributed
addprocs(4)

@everywhere using ParallelOperations

#!!! Notice
# User struct
@everywhere procs() struct TestStruct
    x
    y
end

# Define iterater methods to use REDUCE operations
@everywhere iterate(p::TestStruct) = (p, nothing)
@everywhere iterate(p::TestStruct, st) = nothing

# Functions to execute on remote workers should be known by target worker
@everywhere function f!(a::Array)
    for i in eachindex(a)
        a[i] = sin(a[i])
    end
end

Point-to-point

## Define a variable on worker and get it back
sendto(2, a = 1.0)
b = getfrom(2, :a)
@test b == 1.0

## Specify module (optional)
#!!! Default module is Main
sendto(2, a = 1.0, ParallelOperations)
b = getfrom(2, :a, ParallelOperations)

## Get & Set data by Expr
@everywhere 2 s = TestStruct(0.0, 0.0)
b = 123.0

sendto(2, :(s.x), b)

sendto(2, :(s.y), 456.0)
@everywhere 2 @show s

## Transfer data from worker 2 to worker 3, and change symbol name
transfer(2, 3, :a, :b)
@everywhere 3 @show b

Notice that functions would evaluate the parameter before sending them to remote workers. That means:

sendto(2, a = myid())
b = getfrom(2, :a)

would return b = 1 instead of 2, because function myid is executed on master process.

To send commands to remote, use macros:

@sendto 2 a = myid()
b = getfrom(2, :a)
# b = 2

Here myid is executed on process 2.

This also works with bcast and @bcast (in fact @bcast and @sendto have identical codes)

broadcast

bcast(workers(), :c, 1.0, ParallelOperations)

bcast(workers(), c = [pi/2])

bcast(workers(), f!, :c)

gather

Gathering is executed in the order of the first parameter

d = gather(workers(), :(c[1]))
@test d == 4.0


bcast(pids, a = 1.0)
allgather(pids, :a, :b) # allgather data to new symbol (option)
                        # If ok with unstable type, you could use `allgather(pids, :a)`
b = gather(pids, :b)
@test sum(sum(b)) == 16.0

reduce

@everywhere workers() teststruct = TestStruct(myid(), collect(1:5) .+ myid())
M = reduce(max, workers(), :(teststruct.b))


@everywhere pids a = myid()
allreduce(max, pids, :a) # allreduce data. Use allreduce(max, pids, :a, :b) for new symbol :b
b = gather(pids, :a)
@test sum(b) == 20.0

Scatter

The array to scatter should have the same length as workers to receive

a = collect(1:4)
scatterto(workers(), a, :b, Main)
@everywhere workers() @show b

Commonly used functions

@everywhere workers() x = 1.0

sum(workers(), :x)
allsum(workers(), :x)
maximum(workers(), :x)
allmaximum(workers(), :x)
minimum(workers(), :x)
allminimum(workers(), :x)

Send function to workers

@everywhere fun() = 1

sendto(2, fun)
getfrom(2, :(fun()))

bcast(workers(), fun)
gather(workers(), :(fun()))

Functions with multiple arguments:

@everywhere m(x,y,z) = x+y+z
sendto(2, m, :((1,2,3)...))

Arguments can also be passed by args keyword, which is more user-friendly:

x = 1
sendto(2, m, args = (1,2,3))
sendto(2, m, :($x), args = (2, 3))
gather(m, [1,2], args = (1,2,3))
bcast([1,2], m, args = (1,2,3))

Type-stable

using Distributed
addprocs(1)
@everywhere using ParallelOperations

function testPO()
    @sendto 2 a=5
    a = (@getfrom 2 a)::Int64 # This will restrict the type of a, making both a and b type-stable

    b = a+1
end

function testPOunstable()
    @sendto 2 a=5
    a = @getfrom 2 a

    b = a+1
end

function testPOfun()
    @sendto 2 a=5
    a = (getfrom(2, :a))::Int64 # This will restrict the type of a, making both a and b type-stable

    b = a+1
end

@code_warntype testPO()
@code_warntype testPOunstable()
@code_warntype testPOfun()

TODO

  • Check remotecall functions
  • Benchmark and optimization

Similar packages

ParallelDataTransfer

Package ecosystem

paralleloperations.jl's People

Contributors

islent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

paralleloperations.jl's Issues

Exception cannot be catched from remote call on master process

julia> using Distributed

julia> addprocs(2)
2-element Array{Int64,1}:
 2
 3

julia> @everywhere using ParallelOperations

julia> @everywhere function f(x::Int64)
           return x + 1
       end

julia> @everywhere x = "test"

julia> # Test bcast

julia> bcast([1], f, :x) #! This should have thrown an error, but it did not

julia> @everywhere @show x
x = "test"
      From worker 3:    x = "test"
      From worker 2:    x = "test"

julia> bcast(procs(), f, :x) # Throw error from worker 2
ERROR: On worker 2:
MethodError: no method matching f(::String)
Closest candidates are:
  f(::Int64) at REPL[4]:1 (method too new to be called from this world context.)
top-level scope at none:1
eval at .\boot.jl:331 [inlined]
#6 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\macros.jl:87
#103 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:290
run_work_thunk at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:79     
run_work_thunk at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:88
#96 at .\task.jl:356
Stacktrace:
 [1] #remotecall_fetch#143 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:394 [inlined]
 [2] remotecall_fetch(::Function, ::Distributed.Worker, ::Distributed.RRID) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:386
 [3] #remotecall_fetch#146 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:421 [inlined]
 [4] remotecall_fetch at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:421 [inlined]
 [5] call_on_owner at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:494 [inlined]
 [6] fetch(::Future) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:533    
 [7] sendto at e:\JuliaAstroSim\ParallelOperations.jl\src\ParallelOperations.jl:37 [inlined]
 [8] bcast(::Array{Int64,1}, ::Function, ::Symbol, ::Module) at e:\JuliaAstroSim\ParallelOperations.jl\src\ParallelOperations.jl:87
 [9] bcast(::Array{Int64,1}, ::Function, ::Symbol) at e:\JuliaAstroSim\ParallelOperations.jl\src\ParallelOperations.jl:86       
 [10] top-level scope at REPL[9]:1

julia> @everywhere @show x
x = "test"
      From worker 2:    x = "test"
      From worker 3:    x = "test"

julia> # Test @spawnat

julia> fetch(@spawnat(1, Core.eval(mod, Expr(:call, :($f), :x)))) # Throw error properly
RemoteException(1, CapturedException(MethodError(eval, (mod, :((f)(x))), 0x0000000000006cbe), Any[((::var"#1#2")() at macros.jl:87, 1), (run_work_thunk(::var"#1#2", ::Bool) at process_messages.jl:79, 1), (run_work_thunk at process_messages.jl:88 [inlined], 1), ((::Distributed.var"#96#98"{Distributed.RemoteValue,var"#1#2"})() at task.jl:356, 1)]))

julia> fetch(@spawnat(2, Core.eval(mod, Expr(:call, :($f), :x)))) # Throw error properly
ERROR: On worker 2:
MethodError: no method matching eval(::typeof(mod), ::Expr)
Closest candidates are:
  eval(::Module, ::Any) at boot.jl:331
#3 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\macros.jl:87
#103 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:290
run_work_thunk at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:79     
run_work_thunk at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:88
#96 at .\task.jl:356
Stacktrace:
 [1] #remotecall_fetch#143 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:394 [inlined]
 [2] remotecall_fetch(::Function, ::Distributed.Worker, ::Distributed.RRID) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:386
 [3] #remotecall_fetch#146 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:421 [inlined]
 [4] remotecall_fetch at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:421 [inlined]
 [5] call_on_owner at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:494 [inlined]
 [6] fetch(::Future) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:533    
 [7] top-level scope at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\macros.jl:99

julia> # Test for loop

julia> for p in procs() # Throw error properly
           fetch(@spawnat(p, Core.eval(mod, Expr(:call, :($f), :x))))
       end
ERROR: On worker 2:
MethodError: no method matching eval(::typeof(mod), ::Expr)
Closest candidates are:
  eval(::Module, ::Any) at boot.jl:331
#5 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\macros.jl:87
#103 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:290
run_work_thunk at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:79     
run_work_thunk at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\process_messages.jl:88     
#96 at .\task.jl:356
Stacktrace:
 [1] #remotecall_fetch#143 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:394 [inlined]
 [2] remotecall_fetch(::Function, ::Distributed.Worker, ::Distributed.RRID) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:386
 [3] #remotecall_fetch#146 at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:421 [inlined]
 [4] remotecall_fetch at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:421 [inlined]
 [5] call_on_owner at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:494 [inlined]
 [6] fetch(::Future) at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\Distributed\src\remotecall.jl:533
 [7] top-level scope at REPL[15]:2

julia> for p in [1] #! This should have thrown an error, but it did not
           fetch(@spawnat(p, Core.eval(mod, Expr(:call, :($f), :x))))
       end

julia>

Here is the full code:

using Distributed

addprocs(2)

@everywhere using ParallelOperations
@everywhere function f(x::Int64)
    return x + 1
end

@everywhere x = "test"

# Test bcast
bcast([1], f, :x) #! This should have thrown an error, but it did not
@everywhere @show x 

bcast(procs(), f, :x) # Throw error from worker 2
@everywhere @show x



# Test @spawnat
fetch(@spawnat(1, Core.eval(mod, Expr(:call, :($f), :x)))) # Throw error properly
fetch(@spawnat(2, Core.eval(mod, Expr(:call, :($f), :x)))) # Throw error properly



# Test for loop
for p in procs() # Throw error properly
    fetch(@spawnat(p, Core.eval(mod, Expr(:call, :($f), :x))))
end

for p in [1] #! This should have thrown an error, but it did not
    fetch(@spawnat(p, Core.eval(mod, Expr(:call, :($f), :x))))
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.