Pythonのマルチスレッド
同時に実行複数のスレッドは、マルチスレッド操作は、次のような利点があり、別のプログラムの数のようになります。
- スレッドを使用することに対処するためにバックグラウンドにタスクに長いプログラムを占めることができます。
- 例えば、ユーザは、いくつかのイベント処理をトリガするボタンをクリックするようにユーザーインターフェイスは、より魅力的かもしれ、あなたは、プロセスの進行状況を表示するプログレスバーを開くことができます
- スピードを実行すると、加速する可能性が
- そのようなデータを送受信するために、ユーザ入力、文書リテラシーやネットワークを待っているように実現いくつかのタスク、では、スレッドがより有用です。 この場合、我々はそのようなので、上のメモリ使用量とのようないくつかの貴重なリソースを、解放することができます。
実装プロセス内のスレッドとプロセスが異なっています。 それぞれが注文の履行のためのエントリ、終了シーケンスと手順を実行している別のスレッドがあります。 しかし、スレッドが独立して実行することはできないが、それは、アプリケーションによって制御される複数の実行スレッドを提供し、用途に応じて存在している必要があります。
各スレッドは、スレッドのコンテキストと呼ばれるCPUレジスタの彼自身のセットを持って、スレッドコンテキストは、スレッドのCPUレジスタの状態の最後の実行を反映しています。
命令ポインタ、スタックポインタレジスタは、2つの最も重要なスレッドコンテキストレジスタは、常にプロセスのコンテキスト内で実行されますスレッドは、これらのアドレスは、メモリアドレス空間のスレッドを所有するプロセスをマークするために使用されます。
- スレッドが横取りすることができます(中断)。
- 実行されている他のスレッドでは、スレッドは(も睡眠として知られている)停止状態のままに保持することができる - これは譲歩のスレッドです。
Pythonのスレッドを学び始めます
次の2つの方法で使用Pythonのスレッド:スレッドオブジェクトをラップするための関数やクラスを持ちます。
機能:新しいスレッドを生成するスレッドモジュールstart_new_thread()関数を呼び出します。 構文は次のとおりです。
thread.start_new_thread ( function, args[, kwargs] )
パラメータ説明:
- 機能 - スレッド関数。
- 引数 - 関数に渡されたスレッドパラメータが、彼はタプル型でなければなりません。
- kwargsから - オプション。
例:
#!/usr/bin/python # -*- coding: UTF-8 -*- import thread import time # 为线程定义一个函数 def print_time( threadName, delay): count = 0 while count < 5: time.sleep(delay) count += 1 print "%s: %s" % ( threadName, time.ctime(time.time()) ) # 创建两个线程 try: thread.start_new_thread( print_time, ("Thread-1", 2, ) ) thread.start_new_thread( print_time, ("Thread-2", 4, ) ) except: print "Error: unable to start thread" while 1: pass
次のように上記のプログラムの出力結果は次のとおりです。
Thread-1: Thu Jan 22 15:42:17 2009 Thread-1: Thu Jan 22 15:42:19 2009 Thread-2: Thu Jan 22 15:42:19 2009 Thread-1: Thu Jan 22 15:42:21 2009 Thread-2: Thu Jan 22 15:42:23 2009 Thread-1: Thu Jan 22 15:42:23 2009 Thread-1: Thu Jan 22 15:42:25 2009 Thread-2: Thu Jan 22 15:42:27 2009 Thread-2: Thu Jan 22 15:42:31 2009 Thread-2: Thu Jan 22 15:42:35 2009
スレッドの終了は、一般にスレッド関数の自然な終わりに依存している。また、彼はSystemExitを例外をスロー)(thread.exitスレッド関数を呼び出すスレッドを出るの目的を達成することができます。
スレッドモジュール
Pythonは2標準ライブラリのスレッドとスレッド通すためのサポートを提供します。 スレッドは、低レベル、元のスレッドとシンプルなロックを提供します。
他の方法はスレッドモジュールが用意されています。
- threading.currentThread():現在のスレッドの変数を返します。
- threading.enumerateは():含まれている実行中のスレッドのリストを返します。 実行中のスレッドが終了する前に開始し、それは開始前と終了後にスレッドが含まれていません指します。
- threading.activeCountは():実行中のスレッドの数を返します、とlen(threading.enumerate())と同じ結果を持っています。
方法の使用に加えて、スレッドモジュールは、スレッドのクラスには、次のメソッドを提供し、スレッドを処理するためのスレッド・クラスを提供します。
- 実行():アクティブなスレッドの方法を示すために。
- 開始():スレッドの活動を開始。
- 参加する([時刻]):スレッドが中止されるまで待ちます。通常の終了または未処理の例外をスロー - - スレッドのjoin()メソッドまで、呼び出したスレッドは、サスペンションと呼ばれるこのブロックまたはオプションのタイムアウトが発生します。
- IsAliveのは():スレッドがアクティブで返します。
- getName():スレッドの名前を返します。
- setName():スレッド名を設定します。
スレッドを作成するスレッドモジュールを使用します
その後、直接threading.Threadクラスから継承されたスレッドを、作成方法と実行方法を__init__オーバーライドするスレッディングモジュールを使用します。
#!/usr/bin/python # -*- coding: UTF-8 -*- import threading import time exitFlag = 0 class myThread (threading.Thread): #继承父类threading.Thread def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 print "Starting " + self.name print_time(self.name, self.counter, 5) print "Exiting " + self.name def print_time(threadName, delay, counter): while counter: if exitFlag: thread.exit() time.sleep(delay) print "%s: %s" % (threadName, time.ctime(time.time())) counter -= 1 # 创建新线程 thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) # 开启线程 thread1.start() thread2.start() print "Exiting Main Thread"
次のように上記プログラムの実行結果です。
Starting Thread-1 Starting Thread-2 Exiting Main Thread Thread-1: Thu Mar 21 09:10:03 2013 Thread-1: Thu Mar 21 09:10:04 2013 Thread-2: Thu Mar 21 09:10:04 2013 Thread-1: Thu Mar 21 09:10:05 2013 Thread-1: Thu Mar 21 09:10:06 2013 Thread-2: Thu Mar 21 09:10:06 2013 Thread-1: Thu Mar 21 09:10:07 2013 Exiting Thread-1 Thread-2: Thu Mar 21 09:10:08 2013 Thread-2: Thu Mar 21 09:10:10 2013 Thread-2: Thu Mar 21 09:10:12 2013 Exiting Thread-2
スレッド同期
共通のデータ変更の複数のスレッドが、予期しない結果が発生する可能性がある場合は、データの正確性を確保するために、我々は複数のスレッドを同期する必要があります。
ロックとRLOCKを使用して、スレッドオブジェクトは、単純なスレッドの同期を達成することができ、2つのオブジェクトがメソッドを取得してメソッドをリリースする必要があり、一つのスレッドだけの運転データを可能にそれぞれを必要とする人のために、それはの操作の取得および解放の方法で配置することができます部屋。 次のように:
利点をマルチスレッド化すると、それは同時に複数のタスクを実行できることです(少なくとも、このように感じています)。 スレッドがデータを共有する必要がある場合には、データ同期の問題が存在しなくてもよいです。
すべての要素のリストゼロで、バックからスレッド「セット」前面に一つにすべての要素を、リストや印刷を読み取る担当前後からスレッド「印刷」:ケースを考えてみましょう。
その後、スレッドは「設定」のスレッド「印刷」は、リストを印刷するときに変化し始めたことがあり、それは、データが同期されていないされて半分0の半分出力、であろう。 このような状況を回避するために、我々は、ロックの概念を導入します。
ロックとロック解除 - ロックは、2つの状態があります。 そのようなあなたが最初のロックを取得する必要があり、共有データにアクセスするための「設定」などのスレッドたびに、同期ブロックであるあなたは、すでに別のスレッドがある場合は、そのような「プリント」とは、ロックアップを取得するために、スレッドが「設定」させ、一時停止、;スレッドまで待ちます」印刷を続行するには、set ""アクセスが完了すると、ロックのリリース後、スレッドを聞かせて」。
あなたはすべての出力0または1のいずれか完全な出力の一覧を印刷するとき、このプロセスの後、もはや半分恥ずかし0 1半分は表示されません。
例:
#!/usr/bin/python # -*- coding: UTF-8 -*- import threading import time class myThread (threading.Thread): def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): print "Starting " + self.name # 获得锁,成功获得锁定后返回True # 可选的timeout参数不填时将一直阻塞直到获得锁定 # 否则超时后将返回False threadLock.acquire() print_time(self.name, self.counter, 3) # 释放锁 threadLock.release() def print_time(threadName, delay, counter): while counter: time.sleep(delay) print "%s: %s" % (threadName, time.ctime(time.time())) counter -= 1 threadLock = threading.Lock() threads = [] # 创建新线程 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 threads: t.join() print "Exiting Main Thread"
スレッドのプライオリティキュー(待ち行列)
Pythonのキューモジュールは、同期、FIFO(先入れ先出し)キューキュー、LIFO(うち最初の、の最後の)キューLifoQueue、およびプライオリティキューの優先度つきキューなどのスレッドセーフなキュークラスを提供しています。 これらのキューは、ロック・プリミティブは、複数のスレッドに直接使用することができる実装されます。 あなたは、スレッド間の同期を達成するためにキューを使用することができます。
キューのモジュール一般的に用いられている方法:
- Queue.qsize()キューのサイズを返します。
- Queue.empty()キューが空の場合は、TRUE、FALSE、またはその逆を返します。
- キューがいっぱいになるとQueue.full()、TRUE、FALSE、またはその逆を返します
- サイズおよびMAXSIZE Queue.fullに対応
- Queue.getは([ブロック[、タイムアウト]])キュー、タイムアウト待機時間を取得します。
- Queue.getむしろQueue.get_nowait()(偽)
- Queue.put(アイテム)書き込みキュー、タイムアウト待ち時間
- Queue.put_nowait(アイテム)かなりQueue.put(アイテム、偽)
- Queue.task_done()は、作業の完了後、Queue.task_done()関数は、タスクへの信号キューを完了した送信します
- Queue.join()は実際にキューが空になるまで、他の操作を実行する手段と
例:
#!/usr/bin/python # -*- coding: UTF-8 -*- import Queue import threading import time exitFlag = 0 class myThread (threading.Thread): def __init__(self, threadID, name, q): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.q = q def run(self): print "Starting " + self.name process_data(self.name, self.q) print "Exiting " + self.name def process_data(threadName, q): while not exitFlag: queueLock.acquire() if not workQueue.empty(): data = q.get() queueLock.release() print "%s processing %s" % (threadName, data) else: queueLock.release() time.sleep(1) threadList = ["Thread-1", "Thread-2", "Thread-3"] nameList = ["One", "Two", "Three", "Four", "Five"] queueLock = threading.Lock() workQueue = Queue.Queue(10) threads = [] threadID = 1 # 创建新线程 for tName in threadList: thread = myThread(threadID, tName, workQueue) thread.start() threads.append(thread) threadID += 1 # 填充队列 queueLock.acquire() for word in nameList: workQueue.put(word) queueLock.release() # 等待队列清空 while not workQueue.empty(): pass # 通知线程是时候退出 exitFlag = 1 # 等待所有线程完成 for t in threads: t.join() print "Exiting Main Thread"
上記のプログラムの結果:
Starting Thread-1 Starting Thread-2 Starting Thread-3 Thread-1 processing One Thread-2 processing Two Thread-3 processing Three Thread-1 processing Four Thread-2 processing Five Exiting Thread-3 Exiting Thread-1 Exiting Thread-2 Exiting Main Thread