Pythonのマルチスレッド
スレッドサポートのための2つの標準のPythonライブラリで利用可能とスレッドのスレッドは、前者のために放棄されたサポートでのpython3は、後者を例が続く高いレベルのスレッドライブラリパッケージです。
スレッドを作成します。
Pythonのスレッドで2つの方法があります。
- オブジェクトをインスタンス化し、実行の入口スレッドとして機能オブジェクトの初期化(初期関数)を通過Threading.Thread。
- threading.Threadを継承し、実行機能を無効に。
- モード1:オブジェクトを作成threading.Thread
インポート通し インポート時間 DEF TSTART(引数): time.sleep(0.5) プリント( "%sの実行..." %の引数) __name__ == '__main__'であれば: t1が= threading.Thread(目標= TSTART、引数= ( 'これは、スレッド1')) T2 = threading.Thread(目標= TSTART、引数=( 'これは、スレッド2')) t1.start() t2.start() プリント( "これは主な機能" )
結果:
これが主な機能である ....これは、スレッド2実行されている 。これは、スレッド1動作している....
- オプション2:相続threading.Thread、およびオーバーライドラン
輸入スレッド インポート時の クラスCustomThread(threading.Thread): デフ__init __(自己、thread_name): #ステップ1:基本を呼び出す__init__関数 スーパー(CustomThread、自己).__のinit __(名= thread_name) self._tname = thread_name デフ実行します(自己): ステップ2#:オーバーライドし、実行機能 time.sleep(0.5) プリント( "これは%sが実行されている...." %のself._tname) 場合__name__ == "__main__": T1 = CustomThread( "スレッド1") T2 = CustomThread( "スレッド2") t1.start() t2.start() プリント( "これは主機能です")
道の結果と1。
threading.Thread
上記二つの方法は、本質的に、直接または間接的に使用基づいてthreading.Thread
threading.
Thread
(グループ=なし、 目標=なし、 名前=なし、 引数=() 、 kwargsから= {} )
上記の二つの方法に関連するスレッドを作成します。
輸入スレッド インポート時の クラスCustomThread(threading.Thread): デフ__init __(自己、thread_name、ターゲット=なし): #ステップ1:__init__関数ベースを呼ぶ スーパー(CustomThread、自己).__のinit __(名= thread_name、ターゲット=ターゲット、引数=(thread_name)) self._tname = thread_name DEF実行(自己): #ステップ2:オーバーライドし実行機能 #time.sleep(0.5)# 印刷( "これは%sの実行中である....ラン@" %自己。 _tname) スーパー(CustomThread、自己).RUN() DEFターゲット(引数): time.sleep(0.5) プリント( "これは%sの実行中である....ターゲット@" %の引数) 場合__name__ == "__main__": T1 = CustomThread( "スレッド1"、ターゲット) T2 = CustomThread( "スレッド2"、ターゲット) t1.start() t2.start() プリント( "これは主機能です")
結果:
これが主な機能である 目標@ ....これは、スレッド1実行されている ターゲット@ ....これは、スレッド2実行されています
ショー上記のこのコード:
- スレッドを作成する2つの方法、指定されたパラメータは、最終的にthreading.Threadクラスを渡されます。
- 上書きされていない単語を実行する場合、目的関数は、実行機能体基底クラスのスレッドで呼び出されたスレッドに渡されます。
スレッドモジュールのプロパティとメソッドは、我々は、オブジェクトのメソッドをthreading.Thread何に焦点を当て、ここでは、公式サイトを参照することができます
ここでthreading.Threadはスレッドオブジェクトのメソッドとプロパティを提供します:
- 開始():スレッドが実行する機能を実行するために準備し、CPUスケジューリングを待って、スタートで始まった後、スレッドを作成します。
- 実行():エントリ関数スレッドが実行を開始する、関数本体は、ユーザーが記述した目標関数を呼び出し実行したり、オーバーロードされた関数を実行します。
- ([タイムアウト])参加:保留中のスレッドをブロックすると、コールが終了するまで、この関数を呼び出すか、タイムアウトスレッド。この方法は、通常、他のスレッドが実行を完了するのを待って、メインスレッドで呼び出されます。
- 名前、のgetName()&のsetName():スレッド名関連事業。
- IDENT:整数型スレッド識別子、スレッドはなしに(開始を呼び出す前に)実行を開始する前に、
- isAlive()、is_alive():スタート機能がTrueである実行するための関数を実行する前に、実行された後、もし
- デーモン、isDaemon()&は、setdaemon():デーモンスレッド関連。
これらは、我々はスレッドオブジェクトのスレッド管理とアクセス情報によるスレッドの後にスレッドを作成する方法です。
マルチスレッド実行
それらのいずれかの間に調整及び同期化が存在しない場合、メインスレッドでスレッドを作成した後、各スレッドが終了するまで、メインスレッドに加えて実行される最初から実行されます。
加わります
私たちは、メインスレッドが完了するのを待って実行スレッドを作成し、参加方法、によってブロックされ得ることができます。
輸入スレッド インポート時には、 デフ(引数)をTSTART: 印刷( "%sの実行されている....で:%sの" %(argに、time.time())) time.sleep(1) 印刷( "%sは終了しました! %S」%(引数、time.time()))で あれば__name__ == '__main__': T1 = threading.Thread(目標= TSTART、引数の=( 'これは、スレッド1')) t1.start( ) t1.join()#当前线程阻塞、等待线程执行完成T1 プリント( "これはで主な機能である:%s"の%のtime.time())
結果:
1564906617.43:これはで....スレッド1実行されている 。これは、スレッド1が終了しています!で:1564906618.43 1564906618.43:これは、主な機能であります
メインスレッドが終了すると、現在のプログラムが終了していない任意の制限なしで、すべてのスレッドの終了後に、現在のプロセスが終了するまで待つ必要があります。
上記プログラムt1.join()は次のように実行した結果であり、除去されます。
これは、スレッド1実行されている....で:1564906769.52 1564906769.52:これはで主な機能である 。これは、スレッド1が終了しています!時:1564906770.52
あなたがスレッドによって作成され、スレッドがすぐにこの終了後にメインスレッドの実行を終了し、プログラムが終了終了していないデーモンスレッド(デーモン)を指定することができます。
デーモンデーモンスレッド
輸入スレッド インポート時には、 デフ(引数)をTSTART: 印刷( "%sの実行されている....で:%sの" %(argに、time.time())) time.sleep(1) 印刷( "%sは終了しました!で:%S」%(argに、time.time())) もし__name__ == '__main__': T1 = threading.Thread(目標= TSTART、引数の=( 'これは、スレッド1')) t1.setDaemon(真) t1.start() #t1.join()#当前线程阻塞、等待T1线程执行完成の 印刷( "これはのメイン機能である:%s"の%のtime.time())
結果:
これは、スレッド1実行されている....で:1564906847.85 1564906847.85:これはで主な機能であります
Pythonのマルチプロセッシング
マルチスレッドのpythonを作成するためのモジュールをスレッドに比べ、Pythonのマルチプロセッシング、マルチプロセスを作成するために提供します。プロセスを作成する2つの方法を見てください。
multiprocessing
パッケージは、ほとんどのAPI複製threading
モジュールを。- Pythonのドキュメント
プロセスを作成します。
プロセスとスレッドの作成と同様の方法を作成します。
- Multiprocessing.Processは、オブジェクトをインスタンス化し、新しいプロセスエントリとして実行される関数オブジェクトの初期化(初期関数)を通過させます。
- multiprocessing.Processを継承し、実行機能を無効に。
- モード1:
インポートプロセスマルチプロセッシングから インポートOS、時間 :デフPSTART(名) #1 time.sleep(0.1) プリント( "プロセス名:%sではPID:%S" %(名前、os.getpidを())) __name__場合== "__main__": subproc =プロセス(目標= PSTART、引数=( 'サブプロセス')) subproc.start() subproc.join() プリント( "サブプロセスPID:%S" %のsubproc.pid) プリント(「現在のプロセスPID:%s」は%のos.getpid())
結果:
プロセス名:サブプロセスははPID:4888 4888:サブプロセスのpid 現在のプロセスpid:9912
- オプション2:
インポート・プロセス・マルチプロセッシングから インポートOS、時間 :クラスCustomProcess(プロセス) デフ__init __(自己、P_NAME、ターゲット=なし): #ステップ1:(__init__関数ベース呼び出す) 、スーパー(CustomProcess、自己).__のinit __(名= P_NAME、ターゲット=ターゲット、引数の=(P_NAME)) DEF)(自己を実行します #ステップ2: #1 time.sleep(0.1) プリント( "カスタムプロセス名:%sははPID:%S" %を(self.name、OSを。 GETPID())) もし__name__ == '__main__': P1 = CustomProcess( "process_1") p1.start() p1.join() プリント( "サブプロセスPID:%S" %のp1.pid) プリント(「現在のプロセスPID:%s」は%のos.getpid())
グローバル変数share_dataがあるようマルチスレッディングとして、異なるプロセスが同時にshare_data問題にアクセスし、場合ここでは、考えることができますか?
各プロセスは、別個のメモリアドレス空間と互いに分離を有するため、share_dataを表示するので、異なるプロセスは、異なるアドレス空間における異なる配置されており、アクセスが問題になることはありません。それはノートでなければなりません。
サブプロセスモジュール
今ではマルチプロセス、それが道でプロセスを作成する別の方法であると言います。
Pythonのモジュールは、外部の呼び出し、プログラムの実行中にプログラムSunprocessを提供することができます。
我々は、Python、オープンCMDでメモ帳プログラムを開くか、ある時点でシャットダウンすることができた場合:
>>>インポートサブプロセス >>> subprocess.Popen([ 'cmdを']) <subprocess.Popen 0x0339F550におけるオブジェクト> >>> subprocess.Popen([ 'メモ帳']) <subprocess.Popen 0x03262B70におけるオブジェクト> >>> subprocess.Popen([ 'シャットダウン'、 '-p'])
またはテストネットワーク接続へのpingを使用します。
RES = subprocess.Popen >>>([ 'ピングの'、 'www.cnblogs.com']、STDOUT = subprocess.PIPE).communicate()[0] >>>印刷RESは、 Pingのwww.cnblogs.com [101.37であります.113.127】データの32のバイトを有します。
101.37.113.127からの返信:バイト= 32時間= 1msのTTL = 91
返信101.37.113.127から:バイト= 32時間= 1msのTTL = 91
返信101.37.113.127から:バイト= 32時間= 1msのTTL = 91件の
101.37.113.127からの返信:バイト= 32時間1msのTTL = 91 =
ピング101.37.113.127統計:
パケット:送信= 4、受信した4 =損失= 0(0%損失)、
ラウンドトリップ(ミリ秒単位)の推定時間:
最小= 1ミリ秒、最長=の1msの、平均=用の1ms
Pythonのマルチスレッド、マルチプロセスと比較して
二つの例ではまず見て:
オープン2つのスレッドがパイソン億倍プラス操作され、100万回を行うために別のスレッドを使用し、プラス次の操作を行います。
デフTSTART(引数): VAR = 0 iについてはxrangeで(100000000): VAR + = 1 なら__name__ == '__main__': T1 = threading.Thread(目標= TSTART、引数の=( 'これは、スレッド1') ) T2 = threading.Thread(目標= TSTART、引数=( 'これは、スレッド2')) START_TIME = time.time() t1.start() t2.start() t1.join() t2.join() 印刷( "2つのスレッド・コスト時間:%s"は%(time.time() - START_TIME)) のstart_time = time.time() TSTART( "これは、スレッド0") 印刷( "メインスレッドコスト時間:%s"は% (time.time() - START_TIME))
結果:
2つのスレッド・コスト時間:20.6570000648 メインスレッドコスト時間:2.52800011635
T1およびT2は、2つのスレッドは、メインスレッドの実行と基本的に同じ時間を開いた場合にのみ、上記の例。これは、なぜ、後で説明します。
操作上の二つのプロセスを使用します。
デフPSTART(引数): VAR = 0 iについてはxrangeで(100000000): VAR + = 1 なら__name__ == '__main__': P1 =プロセス(目標= PSTART、引数の=( "1")) P2 =プロセス(ターゲット= PSTART、引数=( "2")) START_TIME = time.time() p1.start() p2.start() p1.join() p2.join() プリント(「2つのプロセスの費用時間:%sの"%(time.time() - START_TIME)) START_TIME = time.time() PSTART(" 0 ") プリント("現在のプロセスコスト時間:%S」%(time.time() - START_TIME))
結果:
二つのプロセスコスト時間:2.91599988937 現在のプロセスコスト時間:2.52400016785
比較分析
ダブルパラレル実行プロセスおよび単一プロセス同じオペレーションコードを実行する基本的に取る同じ、デュアル時間のかかるプロセスは、わずかにより可能性が高い理由であろう余分な時間オーバーヘッドをもたらす、システムコールの作成及び破壊のプロセスです。
しかし、Pythonのスレッドのために、2つのスレッドがほぼ10倍のシングルスレッド、効率の差よりもはるかに高いことが平行時間がかかるで実行します。すなわち、シリアル実行に二つの平行なスレッド場合:
t1.start() t1.join() t2.start() t2.join() #Twoスレッドコスト時間:5.12199997902 #Mainスレッドコスト時間:2.54200005531
あなたは、各実行の3つのスレッドのシリアル実行時間は基本的に同じである見ることができます。
その理由は、デュアルスレッド同時実行ではなく、真の並列実行の性質です。その理由は、GILロックということです。
GILロック
Pythonのマルチスレッドを実現データのセキュリティを確保するために、ロック、現在支配的なPythonインタプリタCPythonのですGIL(グローバルインタプリタロックグローバルインタプリタロック)を、言及しなければならない持ち上げます。どんなに多くのプロセス内のスレッド、GILロックスレッドがCPU上で実行することができます取得する唯一の、リアルタイムのマルチコアプロセッサ。プロセスのために、どんなに多くのスレッドを任意の時点で一つだけのスレッドの実行はありません。CPU集約型スレッドのため、効率では高くはないが、低くてもよいです。PythonのマルチスレッドはIO集約型のプログラムに適しています。プログラムを並列に実行する必要がないために、複数のプロセスを考慮することができます。
スレッドなどを切り替えるロックのマルチスレッドの競合、スレッドのCPUスケジューリングは、時間のオーバーヘッドを持っています。
スレッドとプロセスとの間の差
以下のスレッドとプロセスの簡単な比較であります
- プロセスがリソース割り当ての基本単位であり、スレッドがCPUの実行およびスケジューリングの基本単位です。
- 通信/同期モード:
- プロセス:
- コミュニケーション:コンジット、FIFO、メッセージキュー、セマフォ、共有メモリ、ソケット、ストリームの流れ。
- 同期モード:PVセマフォ、モニター
- スレッド:
- 同期:mutexロックの再帰、条件変数、セマフォ
- 通信:スレッドは、同じプロセスで処理リソースを共用するので、いかなるスレッド間通信は、スレッド同期のためのスレッドとの間の主な通信との間のデータ転送に使用されるプロセスと類似していないがあります。
- CPUは、実際にそのスイッチングおよびスケジューリングコストがプロセスよりも小さい場合よりも、スレッド軽量プロセスのスレッドを実行しています。
- プロセスは、データのみ送信することにより、上記列挙された別のメモリ空間リソース、比較的安全で、IPC(プロセス間通信)を用いて、単離の間にあるので、スレッドの安全性の問題のためにスレッド間のデータ共有の処理は、考慮する必要があります。
- プロセスのシステムがあり、一部を共有するコードセグメントと、データセグメント、ヒープ及びスタック領域、およびオペレーティング・システムを構成する各工程、準備ができ、そこに待っていると三つの状態を操作します。
- このプロセスは、複数のスレッド、スレッド(ファイルディスクリプタ、グローバル変数、ヒープ領域、など)間のリソース共有プロセスを含む変数を登録し、スタック空間はスレッドに対してプライベートであることができます。
- オペレーティングシステムは、プロセスとスレッドのスレッドのためのOSのサポートをハングが多対モデルであれば、それは現在のプロセスがハングアップしますが、プロセスは他のプロセスには影響しませんハング。
- CPU及びシステムがマルチスレッドおよびマルチプロセスをサポートする場合、ハードウェアの最大のパフォーマンスを絞るように、同時に並行して実行する複数のプロセスは、プロセス内の各スレッドは、並列に実行することができます。
スレッドとプロセスのコンテキスト切り替え
スイッチングのプロセスの切り替え処理は、タスク状態セグメントTSSにレジスタの内容を保存するページテーブルを切り替えて、その上のスタックと、多くのことを必要とします。簡単に言えば、それは以下の2つのステップに分けることができます。
- ページのグローバルディレクトリを変更するには、CPUのリニアなアドレス空間は、新しいプロセス宛。
- カーネル・モードとハードウェアコンテキストスタックを切り替え、ハードウェアコンテキストがTSSに記憶されているCPUレジスタの内容を含みます。
、唯一の第二段階が含ま空間に変換するハンドオーバ処理に関与していないプロセスのアドレス空間で実行中のスレッド。
マルチスレッドやマルチプロセスを使用しましたか?
CPU集約型:CPU-プログラムは、計算やデータ処理の多くを必要とします。
I / O集中型:頻繁にI / O操作を必要なプログラム、例えば、データ伝送ネットワークソケット及び読み出しなど。
Pythonはマルチスレッドの並列実行はないので、それは、複数のプロセスCPUを集中的に使用するプログラムの並列実行に適したI / O集中プログラムに適しています。