この記事は、Elixir Advent Calendar 2023 シリーズ12 の23日目です
【本コラムは、5分で読めます】 ※各ライブラリをお試しいただく場合は各自次第で
piacere です、ご覧いただいてありがとございます
下記コラムで行っている「Supervisor経由で10万プロセス起動する負荷」を現代PC+最新Elixirで試すシリーズです
実施PC/Elixir/OTP
- PC
- CPU:i9-9900K 3.60GHz
- メモリ:64 GByte
Erlang/OTP 26 [erts-14.2.1] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]
Elixir 1.16.0 (compiled with Erlang/OTP 26)
ソースコード
import Supervisor.Spec
defmodule PassSupervisor do
def start_link( processes ) do
start = Timex.now()
servers = 1..processes |> Enum.map( &( worker( PassGenServer, [], id: &1 ) ) )
Supervisor.start_link( servers, strategy: :one_for_one )
IO.puts( "Spent Milliseconds=#{Timex.diff( Timex.now(), start, :milliseconds )}" )
end
def cat( parameter, name \\ "0" ) do
GenServer.call( :global.whereis_name( name ), { :cat, parameter } )
end
def pwd( name \\ "0" ) do
GenServer.call( :global.whereis_name( name ), :pwd )
end
end
defmodule PassGenServer do
use GenServer
def start_link() do
{ :ok, pid } = GenServer.start_link( __MODULE__, "" )
#IO.puts( "--- PassGenServer.start_link() PID=#{inspect pid} ---" )
{ :ok, pid }
end
def handle_call( :pwd, _from, _state ) do
{ :ok, result } = File.cwd()
{ :reply, result, "" }
end
def handle_call( { :cat, path }, _from, _state ) do
{ :ok, result } = File.read( path )
{ :reply, result, "" }
end
end
実施結果
10万プロセス生成に、元コラムでは18秒ほどかかっていた処理が、0.7秒で終わるようになっています
iex> PassSupervisor.start_link(100000)
Spent Milliseconds=733
:ok
限界確認
30万プロセスでSystemLimitエラーになりました
iex> PassSupervisor.start_link(300000)
23:11:01.371 [error] Too many processes
** (EXIT from #PID<0.226.0>) shell process exited with reason: shutdown: failed to start child: 262022
** (EXIT) an exception was raised:
** (SystemLimitError) a system limit has been reached
:erlang.spawn_opt(:proc_lib, :init_p, [#PID<0.227.0>, [#PID<0.226.0>, #PID<0.218.0>], :gen, :init_it, [:gen_server, #PID<0.227.0>, #PID<0.227.0>, PassGenServer, "", []]], [:link, :monitor])
(stdlib 5.2) proc_lib.erl:192: :proc_lib.spawn_opt/4
(stdlib 5.2) proc_lib.erl:358: :proc_lib.start_link/5
(basic 0.1.0) lib/basic.ex:24: PassGenServer.start_link/0
(stdlib 5.2) supervisor.erl:420: :supervisor.do_start_child_i/3
(stdlib 5.2) supervisor.erl:406: :supervisor.do_start_child/2
(stdlib 5.2) supervisor.erl:390: anonymous fn/3 in :supervisor.start_children/2
(stdlib 5.2) supervisor.erl:1258: :supervisor.children_map/4
確か、Erlangの設定で解除できたハズですが、パッと思い出せないので、今度、解除してみます
25万プロセスは大丈夫なようです
iex> PassSupervisor.start_link(250000)
Spent Milliseconds=1960
:ok