Ruby
Python

PythonとRubyでthreadとfiberをいくつ作れるか検証して見た

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は無尽蔵に作ることができる。