Concurrency-in-python-implementation-of-threads

提供:Dev Guides
移動先:案内検索

スレッドの実装

この章では、Pythonでスレッドを実装する方法を学びます。

スレッド実装用のPythonモジュール

Pythonスレッドは、プロセスよりもはるかに少ないメモリを占有するため、軽量プロセスと呼ばれることもあります。 スレッドを使用すると、複数のタスクを一度に実行できます。 Pythonでは、プログラムにスレッドを実装する次の2つのモジュールがあります-

  • * <_ thread> *モジュール
  • * <threading> *モジュール

これら2つのモジュールの主な違いは、 <_ thread> モジュールはスレッドを関数として扱うのに対して、 <threading> モジュールはすべてのスレッドをオブジェクトとして扱い、オブジェクト指向の方法で実装することです。 さらに、* <_ thread> モジュールは低レベルのスレッド化で効果的であり、 *<threading> モジュールよりも機能が少なくなります。

<_thread>モジュール

Pythonの以前のバージョンでは、 <thread> モジュールがありましたが、かなり長い間「非推奨」と見なされてきました。 代わりに <threading> モジュールを使用することをお勧めします。 したがって、Python 3では、モジュール「スレッド」は使用できなくなりました。 Python3の後方非互換性のために、「 <_ thread> 」に名前が変更されました。

*<_ thread>* モジュールの助けを借りて新しいスレッドを生成するには、その *start_new_thread* メソッドを呼び出す必要があります。 この方法の動作は、次の構文の助けを借りて理解することができます-
_thread.start_new_thread ( function, args[, kwargs] )

ここに-

  • args は引数のタプルです
  • kwargs は、キーワード引数のオプションの辞書です

引数を渡さずに関数を呼び出したい場合、 args で引数の空のタプルを使用する必要があります。

このメソッド呼び出しはすぐに戻り、子スレッドが開始され、引数のリスト(存在する場合)を使用して関数を呼び出します。 関数が戻ると、スレッドは終了します。

以下は、 <_ thread> モジュールを使用して新しいスレッドを生成する例です。 ここではstart_new_thread()メソッドを使用しています。

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> モジュールの助けを借りて、新しいスレッドの生成を理解するのに役立ちます。

Thread-1: Mon Apr 23 10:03:33 2018
Thread-2: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:37 2018
Thread-2: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:41 2018
Thread-2: Mon Apr 23 10:03:43 2018
Thread-2: Mon Apr 23 10:03:47 2018
Thread-2: Mon Apr 23 10:03:51 2018

<threading>モジュール

*<threading>* モジュールはオブジェクト指向の方法で実装し、すべてのスレッドをオブジェクトとして扱います。 したがって、<_ thread>モジュールよりもはるかに強力で高レベルのスレッドサポートを提供します。 このモジュールはPython 2.4に含まれています。

<threading>モジュールの追加メソッド

*<threading>* モジュールには *<_ thread>* モジュールのすべてのメソッドが含まれますが、追加のメソッドも提供します。 追加の方法は次のとおりです-
  • threading.activeCount()*-このメソッドは、アクティブなスレッドオブジェクトの数を返します
  • threading.currentThread()*-このメソッドは、呼び出し元のスレッドコントロール内のスレッドオブジェクトの数を返します。
  • threading.enumerate()*-このメソッドは、現在アクティブなすべてのスレッドオブジェクトのリストを返します。

スレッドを実装するために、 <threading> モジュールには、次のメソッドを提供する Thread クラスがあります-

  • * run()*-run()メソッドは、スレッドのエントリポイントです。
  • * start()*-start()メソッドは、runメソッドを呼び出してスレッドを開始します。
  • * join([time])*-join()はスレッドが終了するのを待ちます。
  • * isAlive()*-isAlive()メソッドは、スレッドがまだ実行中かどうかを確認します。
  • * getName()*-getName()メソッドは、スレッドの名前を返します。
  • * setName()*-setName()メソッドは、スレッドの名前を設定します。

<threading>モジュールを使用してスレッドを作成する方法は?

このセクションでは、 <threading> モジュールを使用してスレッドを作成する方法を学習します。 次の手順に従って、<threading>モジュールを使用して新しいスレッドを作成します-

  • ステップ1 *-このステップでは、 *Thread クラスの新しいサブクラスを定義する必要があります。
  • ステップ2 *-さらに引数を追加するには、 init(self [、args])*メソッドをオーバーライドする必要があります。
  • *ステップ3 *-このステップでは、run(self [、args])メソッドをオーバーライドして、開始時にスレッドが行うべきことを実装する必要があります。

*<threading>* モジュールを使用して新しいスレッドを生成する方法を学習するには、この例を検討してください。
import threading
import time
exitFlag = 0

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)
      print_time(self.name, self.counter, 5)
      print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
   while counter:
      if exitFlag:
         threadName.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()
thread1.join()
thread2.join()
print ("Exiting Main Thread")
Starting Thread-1
Starting Thread-2

出力

今、次の出力を考慮してください-

Thread-1: Mon Apr 23 10:52:09 2018
Thread-1: Mon Apr 23 10:52:10 2018
Thread-2: Mon Apr 23 10:52:10 2018
Thread-1: Mon Apr 23 10:52:11 2018
Thread-1: Mon Apr 23 10:52:12 2018
Thread-2: Mon Apr 23 10:52:12 2018
Thread-1: Mon Apr 23 10:52:13 2018
Exiting Thread-1
Thread-2: Mon Apr 23 10:52:14 2018
Thread-2: Mon Apr 23 10:52:16 2018
Thread-2: Mon Apr 23 10:52:18 2018
Exiting Thread-2
Exiting Main Thread

さまざまなスレッド状態のPythonプログラム

スレッドの状態には、新規、実行可能、実行中、待機中、デッドの5つがあります。 これらの5つのうち、主に3つの状態(実行中、待機中、および死亡)に焦点を当てます。 スレッドは、実行状態のリソースを取得し、待機状態のリソースを待機します。実行および取得されたリソースの最終リリースは、デッド状態です。

start()、sleep()、およびjoin()メソッドの助けを借りた次のPythonプログラムは、スレッドがそれぞれ実行状態、待機状態、およびデッド状態に入った方法を示します。

  • ステップ1 *-必要なモジュール、<threading>および<time>をインポートします
import threading
import time
  • ステップ2 *-スレッドの作成中に呼び出される関数を定義します。
def thread_states():
   print("Thread entered in running state")
  • ステップ3 *-timeモジュールのsleep()メソッドを使用して、スレッドを2秒待機させます。
time.sleep(2)
  • ステップ4 *-ここで、上記で定義された関数の引数を取るT1という名前のスレッドを作成しています。
T1 = threading.Thread(target=thread_states)
  • ステップ5 *-これで、start()関数の助けを借りて、スレッドを開始できます。 関数を定義するときに設定されたメッセージが生成されます。
T1.start()
Thread entered in running state
  • ステップ6 *-実行が完了した後、ようやくjoin()メソッドでスレッドを強制終了できます。
T1.join()

Pythonでスレッドを開始する

Pythonでは、さまざまな方法で新しいスレッドを開始できますが、その中で最も簡単な方法は、単一の関数として定義することです。 関数を定義した後、これを新しい threading.Thread オブジェクトのターゲットとして渡すことができます。 次のPythonコードを実行して、関数の仕組みを理解します-

import threading
import time
import random
def Thread_execution(i):
   print("Execution of Thread {} started\n".format(i))
   sleepTime = random.randint(1,4)
   time.sleep(sleepTime)
   print("Execution of Thread {} finished".format(i))
for i in range(4):
   thread = threading.Thread(target=Thread_execution, args=(i,))
   thread.start()
   print("Active Threads:" , threading.enumerate())

出力

Execution of Thread 0 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>]

Execution of Thread 1 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>]

Execution of Thread 2 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>]

Execution of Thread 3 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>,
      <Thread(Thread-3579, started 4520)>]
Execution of Thread 0 finished
Execution of Thread 1 finished
Execution of Thread 2 finished
Execution of Thread 3 finished

Pythonのデーモンスレッド

Pythonでデーモンスレッドを実装する前に、デーモンスレッドとその使用法を知る必要があります。 コンピューティングに関しては、デーモンは、データ送信、ファイル転送などのさまざまなサービスの要求を処理するバックグラウンドプロセスです。 不要になった場合は休止状態になります。 同じタスクは、非デーモンスレッドの助けを借りて行うこともできます。 ただし、この場合、メインスレッドは非デーモンスレッドを手動で追跡する必要があります。 一方、デーモンスレッドを使用している場合、メインスレッドはこれを完全に忘れることがあり、メインスレッドが終了すると強制終了されます。 デーモンスレッドに関するもう1つの重要な点は、デーモンスレッドが完了しないか、途中で強制終了された場合に影響を与えない重要でないタスクにのみ使用することを選択できることです。 以下は、Pythonのデーモンスレッドの実装です-

import threading
import time

def nondaemonThread():
   print("starting my thread")
   time.sleep(8)
   print("ending my thread")
def daemonThread():
   while True:
   print("Hello")
   time.sleep(2)
if __name__ == '__main__':
   nondaemonThread = threading.Thread(target = nondaemonThread)
   daemonThread = threading.Thread(target = daemonThread)
   daemonThread.setDaemon(True)
   daemonThread.start()
   nondaemonThread.start()

上記のコードには、> nondaemonThread()*および> daemonThread()*という2つの関数があります。 最初の関数はその状態を出力し、8秒後にスリープしますが、deamonThread()関数は2秒ごとに無期限にHelloを出力します。 私たちは次の出力の助けを借りて、非デーモンとデーモンスレッドの違いを理解することができます-

Hello

starting my thread
Hello
Hello
Hello
Hello
ending my thread
Hello
Hello
Hello
Hello
Hello