2017-01-27 3 views
4

В 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

+1

Может объяснить, почему вы думаете, что это не эквивалент? – Sridhar

+0

Я просто не уверен. – Kokizzu

+1

Вы пытаетесь сравнить производительность процессов нереста в Go vs. Elixir? Просто дикая догадка, но IO может стать вашим узким местом. Кроме того, в вашем коде эликсира есть одна ошибка, вы на самом деле порождаете n + 1 процессов, хотя это не будет иметь большого значения здесь. Чтобы получить осмысленный ориентир, было бы интересно узнать, какую работу вы действительно хотите выполнять в процессах. –

ответ

4

Извините, ребята, бу Я не уверен, что этот код в Go действительно работает так, как ожидалось. Я не эксперт, поэтому, пожалуйста, поправьте меня, если я ошибаюсь. Прежде всего, это печатает z, который, кажется, является текущим значением этого в глобальном масштабе (обычно k*1000) https://play.golang.org/p/a4TJyjKBQh

// test.go 
package main 
import (
    "fmt" 
    "time" 
) 

func main() { 

    for z:=0; z<1000; z++ { 
    go func(x int) { // I'm passing z to the function with current value now 
     fmt.Println(x) 
    }(z) 
    } 

    time.Sleep(1 * time.Nanosecond) 

} 

А также, если я закомментировать Sleep программа выйдет еще до начала какого-либо goroutines (по крайней мере, его не распечатывает результаты). Я был бы рад узнать, что я делаю что-то неправильно, но из этого простого примера кажется, что проблема не в Elixir, а в коде Go. Некоторые Go гуру?

Я также запустить некоторые испытания на моей локальной машине:

go run test.go 500 | wc -l 
72442 # expected 500000 
go run test.go 5000 | wc -l 
76274 # expected 5000000 
+1

ah thank you, i will исправить это – Kokizzu