ホームページ >バックエンド開発 >Python チュートリアル >Python マルチスレッド
マルチスレッドは、複数の異なるプログラムを同時に実行することに似ています。マルチスレッドには次の利点があります:
スレッドを使用すると、長期的なプログラムのタスクをバックグラウンドで処理できます。
ユーザーインターフェイスをより魅力的にすることができ、ユーザーがボタンをクリックして特定のイベントの処理をトリガーすると、プログレスバーがポップアップして処理の進行状況を表示できます
プログラムの実行速度が高速化される可能性があります
一部の待機タスクでは、たとえば、ユーザー入力、ファイルの読み取りと書き込み、ネットワークでのデータの送受信にはスレッドの方が便利です。この場合、メモリ使用量などの貴重なリソースを解放できます。
スレッドは、実行中のプロセスとは依然として異なります。それぞれの独立したスレッドには、プログラム実行のエントリ ポイント、順次実行シーケンス、およびプログラムの終了ポイントがあります。ただし、スレッドは独立して実行できず、アプリケーション プログラム内に存在する必要があり、アプリケーション プログラムは複数のスレッドの実行制御を提供します。
各スレッドには、スレッドのコンテキストと呼ばれる独自の CPU レジスタのセットがあり、スレッドが最後に実行されたときの CPU レジスタの状態を反映します。
命令ポインタとスタック ポインタ レジスタは、スレッド コンテキストで最も重要な 2 つのレジスタであり、スレッドは常にプロセス コンテキストで実行されます。これらのアドレスは、スレッドを所有するプロセスのアドレス空間内のメモリをマークするために使用されます。
スレッドはプリエンプト (中断) できます。
他のスレッドの実行中にスレッドを保留 (スリープとも呼ばれる) することができます。これをスレッド バックオフといいます。
Python スレッドの学習を始めましょう
Python でスレッドを使用するには、スレッド オブジェクトをラップする関数またはクラスの 2 つの方法があります。
機能: スレッドモジュールの start_new_thread() 関数を呼び出して、新しいスレッドを生成します。構文は次のとおりです:
thread.start_new_thread (function, args[, kwargs])
パラメータの説明:
function - スレッド関数。
args - スレッド関数に渡されるパラメータ。タプル型である必要があります。
kwargs - オプションのパラメータ。
例:
#!/usr/bin/python
インポートスレッド
インポート時間
#スレッドの関数を定義する
def print_time(threadName, late):
count = 0
while count
time.sleep(delay)
count += 1
print "%s: %s" % ( threadName, time.ctime(time.time()) )
# スレッドを 2 つ作成します
try:
thread.start_new_thread(print_time, ("Thread-1", 2,))
thread.start_new_thread(print_time, ("Thread-2", 4,) )
以外:
print "エラー: スレッドを開始できません"
while 1:
pass
上記のプログラムを実行すると、出力結果は次のようになります:
Th読む-1: 2009 年 1 月 22 日木 15:42:17
スレッド 1: 2009 年 1 月 22 日木 15:42:19
スレッド 2: 2009 年 1 月 22 日木 15:42:19
スレッド 1: 1 月木22 15:42:21 2009
スレッド-2: 木 1 月 22 日 15:42:23 2009
スレッド 1: 木 1 月 22 日 15:42:23 2009
スレッド 1: 木 1 月 22 日 15:42: 25 2009
スレッド 2: 木 1 月 22 日 15:42:27 2009
スレッド 2: 木 1 月 22 日 15:42:31 2009
スレッド 2: 木 1 月 22 日 15:42:35 2009
スレッドの終了は通常、スレッド関数の自然な終了に依存します。スレッド関数内で thread.exit() を呼び出して、スレッドを終了するという目的を達成するために SystemExit 例外をスローすることもできます。 スレッド モジュールPython は、スレッドとスレッドという 2 つの標準ライブラリを通じてスレッドのサポートを提供します。 thread は、低レベルのプリミティブなスレッドと単純なロックを提供します。 スレッドモジュールによって提供されるその他のメソッド: threading.currentThread(): 現在のスレッド変数を返します。 threading.enumerate(): 実行中のスレッドを含むリストを返します。実行中とは、スレッドの開始後から終了までを指します。開始前と終了後のスレッドは除きます。 threading.activeCount(): 実行中のスレッドの数を返します。これは、len(threading.enumerate()) と同じ結果になります。 使用方法に加えて、スレッド モジュールはスレッドを処理するための Thread クラスも提供します。 Thread クラスは次のメソッドを提供します: run(): スレッドのアクティビティを表すために使用されるメソッド。 start(): スレッドアクティビティを開始します。 join([time]): スレッドが終了するまで待ちます。これにより、スレッドの join() メソッドが異常終了 (通常どおり終了するか、未処理の例外をスロー) が呼び出されるか、またはオプションのタイムアウトが発生するまで、呼び出しスレッドがブロックされます。 isAlive(): スレッドがアクティブかどうかを返します。 getName(): スレッド名を返します。
setName(): スレッド名を設定します。
Threading モジュールを使用してスレッドを作成します
Threading モジュールを使用してスレッドを作成し、threading.Thread から直接継承し、__init__ メソッドをオーバーライドしてメソッドを実行します:
#!/usr/bin /python
Importスレッジinimport time exitflag =0 classmythread(threading.thread):#inherit the parent classthreading.threaddef __ init __(self、swretid、name、and、name、カウンター)。 Print_time (Self.name, Self.Counter, 5) Print "Exning"+Self.nameDef Print_time (ThreadName, Delay, Delay , counter): while counter: if exitFlag: thread.exit() time.sleep(lay) print "%s: %s " % (threadName, time.ctime(time.time ())) counter -= 1 # Create新しいスレッドthread1 = myThread(1, "Thread-1", 1)thread2 = myThread(2, "Thread-2", 2) # スレッドを開始します thread1.start() thread2.start() print "Exiting Main Thread" 上記プログラムの実行結果は次のとおりです スレッド-2の開始メインスレッドを終了しますThread-1: Thu Mar 21 09:10:03 2013Thread-1: Thu Mar 21 09:10:04 2013Thread-2: Thu Mar 21 09:10:04 2013 スレッド 1: 木 3 月 21 日 09:10:05 2013スレッド 1: 木 3 月 21 日 09:10:06 2013スレッド 2: 木 3 月 21 日 09: 10:06 2013スレッド 1 : Thu Mar 21 09:10:07 2013Thread-1 を終了しますThread-2: Thu Mar 21 09:10:08 2013Thread-2: Thu Mar 21 09 :10:10 2013Thread- 2: Thu Mar 21 09:10:12 2013Exiting Thread-2 スレッド同期 複数のスレッドが共同で特定のデータを変更すると、データの正確性を保証するために予期せぬ結果が発生する可能性があります。データを処理するには、複数のスレッドを同期する必要があります。 単純なスレッド同期は、Thread オブジェクトの Lock と Rlock を使用することで実現できます。両方のオブジェクトには、一度に 1 つのスレッドのみで操作する必要があるデータの場合、操作を Acquire メソッドと Release メソッドに配置できます。メソッド間のリリース。以下の通り: マルチスレッドの利点は、複数のタスクを同時に実行できることです (少なくともそう感じられます)。ただし、スレッドがデータを共有する必要がある場合、データの非同期の問題が発生する可能性があります。 次の状況を考えてみましょう。リスト内のすべての要素が 0 で、スレッド「set」は後ろから前にすべての要素を 1 に変更し、スレッド「print」はリストを前から後ろに読み取って印刷する責任があります。 その後、おそらくスレッド「set」が変更を開始すると、スレッド「print」がリストを出力し、出力は半分が 0 で半分が 1 になります。これがデータの非同期です。この状況を回避するために、ロックの概念が導入されました。 ロックには、ロックとロック解除の 2 つの状態があります。 「set」などのスレッドが共有データにアクセスする場合は、まずロックを取得する必要があります。「print」などの別のスレッドがすでにロックを取得している場合は、スレッド「set」を一時停止させます。これは同期ブロックです。スレッド「 Print 」まで アクセスが完了してロックが解除された後、スレッド「set」を続行させます。 このような処理を行うと、リストを印刷する際にオール0かオール1のどちらかが出力されるようになり、半分0と半分1という恥ずかしい光景はなくなりました。 例: #!/usr/bin/python インポートスレッドインポート時間classmythread(threading.thread):def __init __(self、threadid、name、counter):
threading.thread .__ init __(self)
self.threadid = self.name self.name U Self.Counter = Country
DEF RUN (Self):
Print "Starting"+Self.name
#获
、True#optional TimeOUT パラメータの取得に成功、満たされていない場合は常にブロックされますin ロックが取得されるまで # それ以外の場合はタイムアウト後に False を返します threadLock.acquire()threadLock.release()
def print_time(threadName, 遅延, カウンタ):
while counter:
time.sleep(遅延)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
threadLock = threading.Lock()
thread = []
# 新しいスレッドを作成します
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread( 2, "Thread-2", 2)
#新しいスレッドを開始します
thread1.start()
thread2.start()
# スレッドをスレッドリストに追加します
threads.append(thread1)
threads.append(thread2)
# すべてのスレッドが完了するまで待ちます
for t in thread:
t.join()
print "メインスレッドを終了しています"
スレッド優先キュー (キュー)
Python の Queue モジュールは同期スレッドを提供します-safe キュー クラス。FIFO (先入れ先出し) キュー Queue、LIFO (後入れ先出し) キュー LifoQueue、および優先キュー PriorityQueue を含みます。これらのキューはロック プリミティブを実装しており、マルチスレッドで直接使用できます。キューを使用して、スレッド間の同期を実現できます。
Queue モジュールで一般的に使用されるメソッド:
Queue.qsize() キューのサイズを返します
Queue.empty() キューが空の場合は True を返し、それ以外の場合は False を返します
Queue.full()キューがいっぱいの場合は True を返し、それ以外の場合は False を返します
Queue.full は maxsize のサイズに対応します
Queue.get([block[, timeout]]) でキューを取得し、タイムアウト待ち時間
Queue.get_nowait() Queue.get(False)と同等
Queue.put(item)はキューに書き込み、タイムアウト待ち時間
Queue.put_nowait(item)はQueue.put(item, False)と同等
Queue.task_done( ) 作業が完了すると、Queue.task_done() 関数はタスクが完了したキューにシグナルを送信します
Queue.join() は実際には、他の操作を実行する前にキューが空になるまで待機することを意味します
例:
#!/usr/bin/python
インポートキュー
インポートスレッド
インポート時間
exitFlag = 0
クラススレッド (スレッド.スレッド):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
process_data(self.Name, Self.q )
Print "Exning"+Self.name
Def Process_data (ThreadName, Q):
While Not Exitflag:
Queuelock.acquire ()
If not workque.emptt Y (Y ( ):
️ ;S Print "%s処理%s"%(threadName, data) else: queuelock.release () time.sleep (1) ThreadList = ["Thread-", "Thread- 2", "スレッド-3"]nameList = ["1", "Two", "Three", "Four", "Five"]queueLock = threading.Lock()workQueue = Queue.Queue (10) threads = []threadID = 1 # threadListのtNameに対して新しいスレッドを作成します: thread = myThread(threadID, tName, workQueue) thread.start()スレッド。 append(thread) threadID += 1 # nameList の単語に対してキューを埋めるqueueLock.acquire(): workQueue.put(word)queueLock.release()# キューがクリアされるのを待ちます while not workQueue.empty(): pass # スレッドに終了する時間が来たことを通知しますexitFlag = 1 # すべてのスレッドがクリアされるのを待ちますcompletefor t in thread: t.join()print "Exiting Main Thread" 上記のプログラムの実行結果: Starting Thread-1Starting Thread-2
開始スレッド - 3スレッド - 1 処理 1 つスレッド 2 処理 2 つスレッド 3 処理 3 つスレッド 1 処理 4 つスレッド 2 処理 5 つ終了スレッド 3終了スレッド-1スレッドを終了します-2
メインスレッドを終了します