Erlang, Julia, Elixir 연결
이것은 Erlang/Elixir와 Julia의 서로 다른 세계를 연결하기 위한 나의 야심 찬 작은 프로젝트입니다.
이제 Erlang과 Elixir 프로세스는 동일한 BEAM 플랫폼에서 실행되고 PID를 공유하므로 서로 메시지를 보낼 수 있습니다. 하지만 Julia에게 메시지를 보내고 Erlang/Elixir로 다시 보내는 것은 어떻습니까?
Julia REPL에서는 요청 시 자체 모듈 네임스페이스를 사용하여 EvalServer
작업을 생성하는 pServer
작업을 시작합니다.
julia > using Erjulix, Sockets
julia > pServer ( 6000 )
Task (runnable) @ 0x0000000110b30ab0
Elixir REPL에서는 Julia EvalServer
를 요청하고 이를 사용하여 Julia 표현식을 평가하거나 Julia 함수를 호출합니다.
iex ( 1 ) > { :ok , jl , _ } = :ejx_udp . srv ( 6000 ) # get an eval server from Julia
{ :ok , { { 127 , 0 , 0 , 1 } , 54465 } , "Main.##esm#257" }
iex ( 2 ) > :ejx_udp . eval ( jl , "using .Threads" )
{ :ok , [ ] }
iex ( 3 ) > :ejx_udp . call ( jl , :threadid )
{ :ok , 3 }
iex ( 4 ) > :ejx_udp . call ( jl , :factorial , [ 50 ] )
{ :error ,
"OverflowError( " 50 is too large to look up in the table; consider using `factorial(big(50))` instead " )" }
iex ( 5 ) > :ejx_udp . eval ( jl , """ # define a function on the Julia server
...(5)> function fact(x)
...(5)> factorial(big(x))
...(5)> end
...(5)> """)
{:ok, "Main.##esm#257.fact"}
iex(6)> :ejx_udp.call(jl, :fact, [50])
{:ok, 30414093201713378043612608166064768844377641568960512000000000000}
iex(7)> :timer.tc(:ejx_udp, :call, [jl, :fact, [55]])
{527,
{:ok,
12696403353658275925965100847566516959580321051449436762275840000000000000}}
마지막 타이밍은 생성된 Julia fact
함수를 Elixir의 데이터로 호출하고 결과를 다시 가져오는 데 두 세션이 동일한 컴퓨터(MacBook Pro)에서 실행되는 경우 대략 500 µs가 소요된다는 것을 보여줍니다.
iex ( 8 ) > a = Enum . map ( 1 .. 10 , fn _ -> :rand . uniform ( ) end )
[ 0.9414436609049482 , 0.08244595999142224 , 0.6727398779368937 ,
0.18612089183158875 , 0.7414592106015152 , 0.7340558985797445 ,
0.9511971092470349 , 0.7139960750204088 , 0.31514816254491884 , 0.94168140313657 ]
iex ( 9 ) > :ejx_udp . set ( jl , :a , a ) # create variable a on the Julia server
{ :ok , [ ] }
Julia REPL로 돌아가서:
julia > exmod = Erjulix . _ESM[ 1 ] # get access to the server module
Main. # #esm#257
julia > exmod . a # and to the created variable a
10 - element Vector{Any} :
0.9414436609049482
0.08244595999142224
0.6727398779368937
0.18612089183158875
⋮
0.9511971092470349
0.7139960750204088
0.31514816254491884
0.94168140313657
julia > using Plots ....
시스템의 IP 주소와 키를 사용하여 pServer
시작하면 원격 클라이언트와의 통신이 SHA-256으로 암호화됩니다.
julia > getipaddr ()
ip " 192.168.2.113 "
julia > key = Erjulix . genpasswd ( 12 )
" 1XQeFem2NUNw "
julia > pServer ( getipaddr (), 6000 , key)
Task (runnable) @ 0x00000001110e7b90
머신의 IP 주소와 해당 키를 사용하여 로컬 네트워크의 Raspberry Pi에서 pServer
에 액세스합니다.
iex ( 1 ) > :inet . gethostname ( )
{ :ok , 'raspberrypi' }
iex ( 2 ) > key = "1XQeFem2NUNw"
"1XQeFem2NUNw"
iex ( 3 ) > { :ok , jl , _ } = :ejx_udp . srv ( { { 192 , 168 , 2 , 113 } , 6000 , key } )
{ :ok , { { 192 , 168 , 2 , 113 } , 55052 , "j8Gh3G6dPfJm28UpthL0dXew" } , "Main.##esm#258" }
iex ( 4 ) > :ejx_udp . call ( jl , :factorial , [ 20 ] )
{ :ok , 2432902008176640000 }
iex ( 5 ) > :timer . tc ( :ejx_udp , :call , [ jl , :factorial , [ 20 ] ] )
{ 86620 , { :ok , 2432902008176640000 } }
pServer
Julia EvalServer
에 대한 암호화된 네트워크 액세스를 위한 새 키를 생성했습니다. 타이밍은 네트워크 핑퐁이 두 시스템 사이에서 100ms 미만이 걸렸음을 보여줍니다(암호화 없이는 약 70ms가 소요됨).
iex ( 9 ) > :ejx_udp . client ( jl , :exit )
{ :ok , :done }
이는 UDP를 통한 Erlang의 용어 형식을 기반으로 하는 상호 운용성을 위한 프로토타입입니다.
스레드 안전성: 물론 설명된 대로 서버 모듈에 액세스하는 것은 스레드로부터 안전하지 않으므로 동시에 수행해서는 안 됩니다.
보안: UDP-서버 주소와 포트를 공유하면 원격 클라이언트가 파일 시스템에 액세스할 수 있습니다. pServer
에 키를 제공하면 데이터 전송에 SHA-256 암호화가 사용됩니다.
ErlangTerm.jl
에 의존합니다.jwerl
포크에 의존합니다. 기본 저장소를 업데이트하는 데 문제가 있습니다. Julia 레지스트리에서 사용 가능한 경우 다음을 사용하여 패키지를 설치할 수 있습니다.
pkg > add Erjulix
Hex에서 사용할 수 있는 경우 mix.exs
의 종속성 목록에 erjulix
추가하여 Elixir에 패키지를 설치할 수 있습니다.
def deps do
[
{ :erjulix , "~> 0.1.0" }
]
end
ExDoc으로 문서를 생성하고 HexDocs에 게시할 수 있습니다. 게시된 문서는 https://hexdocs.pm/erjulix에서 찾을 수 있습니다.