PythonとRubyでそれぞれthreadをいくつくらい作れるのか検証して見た。
また軽量スレッドのFiberでやるとどうなるのかも検証。
検証環境
- MacOSX 10.12 (Sierra)
- ruby 2.5.0
- python 3.6.1
スタックサイズなどは特にいじらずデフォルトのままで試している。
Threadの場合
Pythonの検証用コード
num_threads.py
import threading,time,sys
def t():
time.sleep( 1000 )
tc = 0
try:
while 1:
p = threading.Thread( target=t, args=() )
p.start()
tc += 1
print(tc, file=sys.stderr)
finally:
print(tc, file=sys.stderr)
実行結果 : 2048スレッドまで。
...
2047
Traceback (most recent call last):
File "num_threads.py", line 10, in <module>
p.start()
File "/Users/murase/.pyenv/versions/miniconda3-4.1.11/envs/ml/lib/python3.6/threading.py", line 846, in start
_start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
Rubyの場合
num_threads.rb
count = 0
begin
loop do
t = Thread.new do
sleep 1.0
end
count += 1
$stderr.puts count
end
ensure
$stderr.puts count
end
実行結果 : 2046まで。
...
2046
Traceback (most recent call last):
4: from num_threads.rb:3:in `<main>'
3: from num_threads.rb:3:in `loop'
2: from num_threads.rb:4:in `block in <main>'
1: from num_threads.rb:4:in `new'
num_threads.rb:4:in `initialize': can't create Thread: Resource temporarily unavailable (ThreadError)
どちらもほぼ$2^{11}$まで作れるのがデフォルトの挙動らしい。
Fiberの場合
Pythonに言語レベルでFiberはないので、fibersというライブラリを使う。pip install fibers
でインストールできる。
fiberの検証コードはこちら。
num_fibers.py
import fibers,time,sys
def t():
a = 10 # 検証用に適当なローカル変数を作っている
f = fibers.Fiber.current()
f.parent.switch()
tc = 0
try:
fs = []
while 1:
f = fibers.Fiber(target=t, args=() )
f.switch()
fs.append(f)
tc += 1
print(len(fs), file=sys.stderr)
if tc > 32768:
break
finally:
print(tc)
Rubyは標準ライブラリにFiberがある。コードは以下のようになる。
num_fibers.rb
count = 0
begin
fs = []
loop do
f = Fiber.new do
a = 10
Fiber.yield
end
f.resume
fs << f
count += 1
$stderr.puts count
break if count > 32768
end
ensure
$stderr.puts count
end
どちらの場合も最大値までfiberを作ることができた。
まとめ
どちらの言語もthreadは2000くらい、fiberは無尽蔵に作ることができる。