[python]GILグローバルインタプリタロック

2692 ワード

GILって何?
GILはPythonの特性ではなく、Python解析器(CPython)を実装する際に導入された概念であり、CPythonはほとんどの環境でデフォルトのPython実行環境である.GIL全称gloabl interpreter lock(グローバル解釈器ロック)、公式解釈:
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)
これは主にcpython解釈器にとって、他の解釈器は違います.
GILの影響
GILは、「1つのスレッドがPythonを実行し、他のN個の睡眠またはI/O.を待つ」という原則に従う(すなわち、同じ時点で共有リソースへのアクセスが1つのスレッドのみであることを保証する).
以前はGILグローバルロックがあると思っていた存在を見ていましたが、マルチスレッドではなぜ自分でロックをかけるのか、後で考えが間違っていることに気づきました.一つのスレッドが終わってから別のスレッドを実行するのを待つわけにはいきません.そのマルチスレッドは存在する必要がありません.
#   GIL   ,               
total = 0
def add():
    global total
    for i in range(1000000):
        total += 1

def desc():
    global total
    for i in range(1000000):
        total -= 1

import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print(total)

この例では、2つのスレッドがそれぞれ1つのグローバル変数totalを1000000回加算および減算しますが、結果は0ではありません.実行するたびに結果が異なります.
この結果の原因はGILが実際に解放されるためであり、pythonには2つのマルチタスク処理があります.
1.協同型マルチタスク処理:一つのスレッドがいつ睡眠を開始しても或いはネットワークI/Oを待つ時、GILロックを解除する
2.プリエンプトマルチタスク処理:1つのスレッドがPython 2で1000バイトコード命令を間欠的に実行したり、Python 3で15ミリ秒間欠的に実行したりすると、GILは放棄され、他のスレッドは実行できます.
このように解釈するとGILはあまり影响がないような気がしますが、どうせ切り替えられるのでしょうか.それはなぜGILの存在によってpythonのマルチスレッドが単一スレッドよりも遅いと言われているのか、私の理解では、シングルコアCPUでは何も変わらない(性能損失もあるかもしれない)が、マルチコアCPUでは問題が大きくなり、異なるコア上のスレッドが同じ時刻に1つしか実行できないため、マルチコアCPUの優位性を利用することができず、逆に異なるコア間を切り替える際にソースの浪費をもたらし、かえってシングルコアCPUよりも遅い.
解決策
1.マルチスレッドが比較的非効率な場合、Threadライブラリの代わりにmultiprocessライブラリを使用できます.つまり、マルチスレッドではなくマルチプロセスを使用し、各プロセスには独自のGILがあるため、プロセス間のGIL争いも発生しません.しかし、プロセス間のデータ通信や同期の困難など、他にも多くの問題が発生します.
2.マルチスレッドもそうではありません.IO密集型の操作では、マルチスレッドを使うと効果的で、マルチプロセスよりも悪くなく、より良いことができます.
3.他の解析器を使用します.JPythonやIronPythonのような解析器は言語の特性を実現するため、GILの助けは必要ありません.しかし,Java/C#を解析器実装に用いたため,コミュニティの多くのC言語モジュールの有用な特性を利用する機会も失った.だからこれらの解析器もずっと小さいです.結局、機能と性能は初期に前者を選ぶ.
4.GILの改善を待つ.pythonコミュニティもGILを改善し、GILを除去しようと努力しています.各小バージョンで多くの進歩があった.
まとめ
GILはレイヤ実装に関わるため,複雑であり,完全に理解することは困難である.でも2点だけ覚えておけば:
1.IO密集型の操作の下で、マルチスレッドはやはり可能である.例えばネットワーク通信ではtime.sleep()遅延時.
2.CPU密集型の操作では、マルチスレッド性能は逆に単一スレッドに及ばず、この場合はマルチプロセスしか使用できない.
GILがマルチスレッドの効率を低下させる理由については、以下の文書を参照してください.
リファレンスリンク
1.GILを深く理解する:高性能とスレッドの安全なPythonコードをどのように書くか2.PythonのGILは何ですか.マルチスレッドの性能はいったいどうですか.pythonの下で同じコードで、マルチコアマルチスレッドはどうしてシングルコアマルチスレッドよりずっと遅いのですか?4.Python 3高級プログラミングと非同期IO同時プログラミング