Pythonマルチスレッドマルチプロセスグローバル解釈器ロックGIL join


Pythonコードの実行は、Python仮想マシン(解釈器メインサイクルとも呼ばれる)によって制御される.Pythonは設計当初から主サイクル中であると同時に1つのスレッドのみが実行されることを考慮しており,単一CPUのシステムで複数のプロセスを実行するようにメモリに複数のプログラムを格納できるが,任意の時点で1つのプログラムだけがCPUで実行される.同様に、Python解釈器では複数のスレッドを「実行」することができるが、任意の時点で1つのスレッドだけが解釈器で実行される.
上は公式の言い方で、通俗的に言えば、pythonプログラム自体はcpuの1つのスレッドしか占めていないので、pythonのいわゆるマルチスレッドプログラミングは単一CPUの場合のマルチプロセスプログラミングに似ています.
CPUの場合のマルチプロセス運転について説明します.
複数のプロセスシーケンスをスケジューラで調整した後、順番にcpuに入力して計算します.マルチタスクをいくつかの渓流と見なすことができます.そして、スケジューラは最後の融通口で、融通した後にCPUに流入して計算しますが、異なるのは、単位時間当たりにCPUに流入する量は一定で、タスクをマルチプロセスに分けてCPU計算を行う量は分割前のCPU計算量と基本的に同じです.
したがって,計算密集型のタスクに対しては,マルチプロセスに分けて計算時間を減らすのではなく,スケジューリング時間を増やすため,かえって増加する.
IO密集型のタスクでは、IO密集型はCPUに対する占有量が相対的に少ないため、CPUがフル負荷状態にならず、IOの待ち時間を減らすことができる.
なぜIOは時間を節約でき、計算型が密集してはいけないのですか?
私は、計算が密集しているタスクは、マルチプロセスに分割されているかどうかにかかわらず、CPUがタスク実行中に常にフル負荷(この完全なタスクを直接実行しても、順序やスケジューリング方式で複数のプロセスを実行しても)であり、空きリソースは存在しないと考えています.
一方、IO密集型のタスクは、CPUでもIOでも、ほとんどリソースをフル負荷にしないので、プロセスを分割して、分割した部分にこれらのリソースを利用させることができ、時間を節約することができます.
次の説明もいいです.
単一cpuマルチパスプロセスシステムには、次のような特徴があります.
1マクロ的に見ると、いくつかのプログラムは「同時に行う」.すなわち、彼らは前後して与えられた運行を開始し、いずれも終了していない.
②微視的に見ると、いくつかのプログラムは「交互に実行する」.単一のcpuプロセスでは、cpuを順番に占有するだけです.
CPUは各プロセス間を往復し,この高速切替はマルチプログラム設計となる.各プロセスには独自の制御プロセスがあり、各プロセスは独立して実行されます.実際には物理プログラムカウンタが1つしかないので、プログラムが実行されるたびに、彼の論理カウンタは設計されたプログラムカウンタにロードされます.時間が経つにつれて、プログラムが終了すると、物理プログラムカウンタはメモリ内のプロセスの論理プログラムカウンタに保存される.すべてのプロセスは進展していますが、1つの与えられた瞬間に1つのプロセスだけが実際に実行されます.
Pythonのマルチスレッドを見てみましょう
まず、pythonは実行中の各時点で、実際には1つのスレッドしか動作していないことを確認します.開いているマルチスレッドは、実行可能なコードにコンパイルされてメモリに格納され、タスクスケジューラによってこの「スレッドフロー」に格納され、このスケジューリングを実行するのは
グローバルインタプリタロック(GIL).
いくつかのpythonマルチスレッドに関するキーワードを紹介します:threadとthreading、デーモンスレッド、join
Pythonには2つのスレッド操作モジュールthreadとthreadingがあり、threadでマルチスレッドを作成すると、メインスレッドが終了すると、すべてのスレッドが強制的に終了し、警告もなく正常なクリアは行われません.threadingモジュールは、重要なサブスレッドが終了してからプロセスが終了することを保証します.
デーモンスレッド:メインスレッドが終了するときに、サブスレッドが完了するのを待つ必要がない場合は、これらのスレッドのdaemonプロパティを設定します.すなわち、スレッド開始(thread.start()を呼び出す)前にsetDaemon()関数設定スレッドを呼び出すdaemonフラグ(thread.setDaemon(True))は、このスレッドが「重要ではない」ことを示す.
join:pythonメインプログラムはデフォルトのスレッドに相当しますが、threadingで新しいスレッドを作成すると、startメソッドに従ってメインプログラムと並列に計算されます.joinを設定しないと、このスレッドstartからpythonメインプログラムと並列に計算されます.joinの役割は、pythonメインプログラムで複数のスレッドを開きjoinに設定すると、これらのスレッドがメインプログラムに添付されます.
#coding=utf-8
import threading
import time
threads=[]
def func(x):
    print 'hello',x
    time.sleep(x)
    print 'I have sleep %d seconds'%x
cur=time.clock()

for i in range(3):
    threads.append(threading.Thread(target=func,args=(i+2,)))
for thread in threads:
    thread.start()
    thread.join()
print 'finish!'
print time.clock()-cur
出力:
hello 2
I have sleep 2 seconds
hello 3
I have sleep 3 seconds
hello 4
I have sleep 4 seconds
finish!
9.0039654844
#coding=utf-8
import threading
import time
threads=[]
def func(x):
    print 'hello',x
    time.sleep(x)
    print 'I have sleep %d seconds'%x

for i in range(3):
    threads.append(threading.Thread(target=func,args=(i+2,)))
for thread in threads:
    thread.start()
    #thread.join()
print 'finish!'
出力:
hello 2
hello 3
hellofinish! 
4
I have sleep 2 seconds
I have sleep 3 seconds
I have sleep 4 seconds
説明します.
hellofinish! 
4
ここでprint'hello',4を並列に実行した.        print 'finish!'
前の項目はprint'hello'に相当し、文の末尾のカンマとprint'4'に注意してください.
スケジューリング時に後ろの1本が真ん中になると、上記の結果が印刷されます.
pythonマルチプロセス:
Pythonはマルチプロセスタスクを処理するmultiprocessingを提供しており、興味があれば見ることができます.