В Go я могу создать goroutines как это (EDITED как сообщает kelu-thatsall «s ответ):Как создать процесс n-k в процессе эрланга или эликсира?
// test.go
package main
import (
"fmt"
"os"
"strconv"
"sync"
"runtime"
)
func main() {
var wg sync.WaitGroup
if len(os.Args) < 2 {
os.Exit(1)
}
k, ok := strconv.Atoi(os.Args[1])
if ok != nil {
os.Exit(2)
}
wg.Add(k * 1000)
for z := 0; z < k*1000; z++ {
go func(x int) {
defer wg.Done()
fmt.Println(x)
}(z)
if z%k == k-1 {
// @mattn: avoid busy loop, so Go can start processing like BEAM do
runtime.Gosched()
}
}
wg.Wait()
}
В результате в Go 1.8.0 (64-разрядная версия):
# shell
$ go build test.go ; for k in 5 50 500 5000 50000 500000; do echo -n $k; time ./test $k > /dev/null; done
5
CPU: 0.00s Real: 0.00s RAM: 2080KB
50
CPU: 0.06s Real: 0.01s RAM: 3048KB
500
CPU: 0.61s Real: 0.12s RAM: 7760KB
5000
CPU: 6.02s Real: 1.23s RAM: 17712KB # 17 MB
50000
CPU: 62.30s Real: 12.53s RAM: 207720KB # 207 MB
500000
CPU: 649.47s Real: 131.53s RAM: 3008180KB # 3 GB
Каков эквивалентный код в Erlang или Elixir? (EDITED как сообщает patrick-oscity «ы комментарий)
То, что я пытался до сих пор является следующее:
# test.exs
defmodule Recursion do
def print_multiple_times(n) when n <= 1 do
spawn fn -> IO.puts n end
end
def print_multiple_times(n) do
spawn fn -> IO.puts n end
print_multiple_times(n - 1)
end
end
[x]=System.argv()
{k,_}=Integer.parse(x)
k=k*1000
Recursion.print_multiple_times(k)
В результате в эликсира 1.4.2 (ГЭР-8.2.2):
# shell
$ for k in 5 50 500 5000 50000 ; do echo -n $k; time elixir --erl "+P 90000000" test.exs $k > /dev/null; done
5
CPU: 0.53s Real: 0.50s RAM: 842384KB # 842 MB
50
CPU: 1.50s Real: 0.62s RAM: 934276KB # 934 MB
500
CPU: 11.92s Real: 2.53s RAM: 1675872KB # 1.6 GB
5000
CPU: 122.65s Real: 20.20s RAM: 4336116KB # 4.3 GB
50000
CPU: 1288.65s Real: 209.66s RAM: 6573560KB # 6.5 GB
Но я не уверен, являются ли эти два эквивалентными. Они ?
EDIT Укороченный вариант как комментарий mudasobwa «s не дает правильный вывод
# test2.exs
[x]=System.argv()
{k,_}=Integer.parse(x)
k=k*1000
1..k |> Enum.each(fn n -> spawn fn -> IO.puts n end end)
Результат for k in 5 50 500 5000 50000 ; do echo -n $k; time elixir --erl "+P 90000000" test.exs $k | wc -l ; done
:
5
CPU: 0.35s Real: 0.41s RAM: 1623344KB # 1.6 GB
2826 # does not complete, this should be 5000
50
CPU: 1.08s Real: 0.53s RAM: 1691060KB # 1.6 GB
35062
500
CPU: 8.69s Real: 1.70s RAM: 2340200KB # 2.3 GB
373193
5000
CPU: 109.95s Real: 18.49s RAM: 4980500KB # 4.9 GB
4487475
50000
erl_child_setup closed
Crash dump is being written to: erl_crash.dump...Command terminated by signal 9
CPU: 891.35s Real: 157.52s RAM: 24361288KB # 24.3 GB
Не испытывая 500м для эликсира, потому что это слишком долго, и +P 500000000
аргумент is bad number of processes
Может объяснить, почему вы думаете, что это не эквивалент? – Sridhar
Я просто не уверен. – Kokizzu
Вы пытаетесь сравнить производительность процессов нереста в Go vs. Elixir? Просто дикая догадка, но IO может стать вашим узким местом. Кроме того, в вашем коде эликсира есть одна ошибка, вы на самом деле порождаете n + 1 процессов, хотя это не будет иметь большого значения здесь. Чтобы получить осмысленный ориентир, было бы интересно узнать, какую работу вы действительно хотите выполнять в процессах. –