実際、そうではありません。それぞれのスレッドはまさにそのインタープリタの新しいスレッドです。
これはOSによって管理される実際のスレッドであり、Python仮想マシン内のPythonコードのための内部管理スレッドではありません。
非常にOSベースのスレッドがPythonオブジェクトを混乱させないようにするには、GILが必要です。
1つのCPU上に1つのスレッドを、もう1つのスレッドにもう1つのスレッドを想像してください。アセンブリで書かれた純粋な並列スレッド。両方同時にレジストリ値を変更しようとしています。まったく望ましい状況ではありません。同じメモリ位置にアクセスするためのアセンブリ命令は、いつどこで移動するのかをスクランブリングしてしまいます。最終的に、そのようなアクションの結果は、容易にセグメンテーション違反につながる可能性があります。さて、C言語で記述すると、Cはその部分を制御するので、これはCコードでは起こりません。 GILはCレベルのPythonコードでも同じです。そのため、Pythonオブジェクトを実装しているコードは、Pythonオブジェクトを変更するときにそのアトミック性を失わないようにします。他のスレッドがその中からいくつかの要素を削除したために、他のスレッドでただ下にシフトされているリストに値を挿入するスレッドを想像してみてください。 GILがなければ、これはクラッシュします。
GILは、スレッド内のコードのアトミック性については何もしません。これは内部メモリ管理のためのものです。
deque()のようなスレッドセーフなオブジェクトを持っていても、一度に複数の操作をロックしなくても間に挿入された別のスレッドから結果を得ることができます。そしておっと、問題が起こる!
たとえば、あるスレッドがスタックからオブジェクトを取り出し、何かをチェックし、条件が正しければそれを削除します。
stack = [2,3,4,5,6,7,8]
def thread1():
while 1:
v = stack[0]
sleep(0.001)
if v%2==0: del stack[0]
sleep(0.001)
もちろん、これはばかげているので、これを避けるにはstack.pop(0)を使用してください。しかしこれは一例です。
そして、それぞれ0をスタックに追加する別のスレッドを用意しましょう。002秒:あなたがしなければ
def thread2():
while 1:
stack.insert(0, stack[-1]+1)
sleep(0.002)
:今すぐスレッド2()は正確に(スレッド1の間に新しいアイテムを積み重ねしようとする可能性は低い、どこが
thread(thread2,())
sleep(1)
thread(thread1,())
は、瞬間があるでしょう)の検索削除。したがって、thread1()はチェックされているアイテムの代わりに新しく追加されたアイテムを削除します。結果は私たちの希望に従わない。だから、GILは私たちのスレッドで何をしているのか、もっと基本的な意味でスレッド同士が何をしているのかを制御しません。
イベントのチケットを購入するサーバーを作成したとします。 2人のユーザーが同じチケットを同時に購入しようとします。あなたが慎重でない場合、ユーザーは他の人の上に座って終了することがあります。
スレッドセーフオブジェクトは、アクションを実行するオブジェクトであり、最初のアクションが完了するまで別のアクションを実行することはできません。
たとえば、deque()を1つのスレッドで反復処理している途中で別のスレッドが何かを追加しようとすると、append()は最初のスレッドが反復処理されるまでブロックします。これはスレッドセーフです。
いくつかの操作では、複数の命令を同期させる必要があります。これは、Pythonを別のスレッドで解釈できるようにするためです。 GILは、Pythonプログラムを決して*同期化することは決してありません。asyncioとは何も関係ありません。 - PythonオブジェクトがPythonレベルではなく、Cレベルでスレッドセーフであることを確認するだけです。 –