Pythonでのスレッドといえば、GIL(Global Interpreter Lock)があるので同時にはひとつのスレッドしか実行できない
という話らしいです。
スレッド状態 (thread state) とグローバルインタプリタロック (global interpreter lock)
動的言語総まとめ : PythonのGILが徹底改善されるも廃止はされない。SqueakがAndroidに移植された。
Pythonのマルチスレッドで気を付けるべきこと | 凡人のブログ
ところで、このスレッドってOSのネイティブスレッドなのでしょうか?ちょっと確認してみたくなりました。
環境
確認した環境は、こちら。
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.2 LTS Release: 18.04 Codename: bionic $ python3 -V Python 3.6.7
Ubuntu Linux 18.04 LTS、Python 3.6です。
確認
こんなプログラムを用意。
thread-example.py
import threading import time def run(): current_thread_name = threading.current_thread().getName() print("start Thread = %s" % current_thread_name) time.sleep(10) print("end Thread = %s" % current_thread_name) print("start!!") threads = [threading.Thread(target = run, name = "Thread-%d" % (i + 1)) for i in range(5)] for thread in threads: thread.start() for thread in threads: thread.join() print("finish!!")
スレッドを5つ用意して開始、各スレッドは10秒待機して終了します。
まずは、実行。
$ time python3 thread-example.py start!! start Thread = Thread-1 start Thread = Thread-2 start Thread = Thread-4 start Thread = Thread-3 start Thread = Thread-5 end Thread = Thread-4 end Thread = Thread-3 end Thread = Thread-2 end Thread = Thread-1 end Thread = Thread-5 finish!! real 0m10.039s user 0m0.030s sys 0m0.000s
10秒で終わりました。
では、このプログラムを実行中に
$ time python3 thread-example.py
もうひとつのターミナルで、プロセスから派生したスレッドを確認してみます。
$ ps aux -L | grep python3 | grep thread-example.py xxxxx 13748 13748 0.1 6 0.0 407140 9912 pts/0 Sl+ 00:24 0:00 python3 thread-example.py xxxxx 13748 13749 0.0 6 0.0 407140 9912 pts/0 Sl+ 00:24 0:00 python3 thread-example.py xxxxx 13748 13750 0.0 6 0.0 407140 9912 pts/0 Sl+ 00:24 0:00 python3 thread-example.py xxxxx 13748 13751 0.0 6 0.0 407140 9912 pts/0 Sl+ 00:24 0:00 python3 thread-example.py xxxxx 13748 13752 0.0 6 0.0 407140 9912 pts/0 Sl+ 00:24 0:00 python3 thread-example.py xxxxx 13748 13753 0.0 6 0.0 407140 9912 pts/0 Sl+ 00:24 0:00 python3 thread-example.py
全部で6つありますね。ひとつ多いのは、メインスレッドですね。というわけで、OSネイティブなスレッドのようです。
ソースコードをさらっと見てみましょう。
https://github.com/python/cpython/blob/v3.6.7/Lib/threading.py#L32
https://github.com/python/cpython/blob/v3.6.7/Python/thread.c#L84-L87
https://github.com/python/cpython/blob/v3.6.7/Python/thread_pthread.h#L159-L178
POSIXスレッドみたいですね。
Windowsの場合は…?
https://github.com/python/cpython/blob/v3.6.7/Python/thread.c#L89-L92
https://github.com/python/cpython/blob/v3.6.7/Python/thread_nt.h#L145-L151
ところで、「GILがある割にはスリープするプログラムは10秒で終わっているのでは?」と思うかもなのですが、
これはスリープ時にGILを解放するからでしょうねぇ…。
karky7のブログ: PythonのGILについて簡単に調べてみました
ちらっとソースコードを見てみると、そうみたいですね。
https://github.com/python/cpython/blob/v3.6.7/Modules/timemodule.c#L1447-L1449
Py_BEGIN_ALLOW_THREADS ... Do some blocking I/O operation ... Py_END_ALLOW_THREADS