ホームページ > バックエンド開発 > Python チュートリアル > Python のマルチスレッドを深く理解する初心者必読の本。

Python のマルチスレッドを深く理解する初心者必読の本。

黄舟
リリース: 2016-12-14 17:52:59
オリジナル
1276 人が閲覧しました

例 1
5 つの異なる URL をリクエストします:
シングルスレッド

import time
import urllib2
   
defget_responses():
  urls=[
    ‘http://www.baidu.com',
    ‘http://www.amazon.com',
    ‘http://www.ebay.com',
    ‘http://www.alibaba.com',
    ‘http://www.jb51.net'
  ]
  start=time.time()
  forurlinurls:
    printurl
    resp=urllib2.urlopen(url)
    printresp.getcode()
  print”Elapsed time: %s”%(time.time()-start)
   
get_responses()
ログイン後にコピー

出力は次のとおりです:
http://www.baidu.com200
http://www.amazon.com200
http:// www .ebay.com200
http://www.alibaba.com200
http://www.jb51.net200
経過 time: 3.0814409256

説明:
URLは順番にリクエストされます
CPUが1つのURLから応答を取得しない限り、次のURLをリクエストしません
ネットワークリクエストには長い時間がかかるため、CPUは戻り時間を待っていますのネットワーク要求はアイドル状態です。
マルチスレッド

import urllib2
import time
from threading import Thread
   
classGetUrlThread(Thread):
  def__init__(self, url):
    self.url=url
    super(GetUrlThread,self).__init__()
   
  defrun(self):
    resp=urllib2.urlopen(self.url)
    printself.url, resp.getcode()
   
defget_responses():
  urls=[
    ‘http://www.baidu.com',
    ‘http://www.amazon.com',
    ‘http://www.ebay.com',
    ‘http://www.alibaba.com',
    ‘http://www.jb51.net'
  ]
  start=time.time()
  threads=[]
  forurlinurls:
    t=GetUrlThread(url)
    threads.append(t)
    t.start()
  fortinthreads:
    t.join()
  print”Elapsed time: %s”%(time.time()-start)
   
get_responses()
ログイン後にコピー

出力:
http://www.jb51.net200
http://www.baidu.com200
http://www.amazon.com200
http://www.alibaba. com200
http://www.ebay.com200
経過 time:0.689890861511

説明:

プログラムの実行時間の向上を意識しました
スレッド内のネットワークリクエストが返されるのを待っているときに、CPUの待ち時間を短縮するためにマルチスレッドプログラムを作成しました。他のスレッドに切り替えて、他のスレッドでネットワーク要求を実行できます。
1 つのスレッドが 1 つの URL を処理することを期待しているため、スレッド クラスをインスタンス化するときに URL を渡します。
スレッドの実行とは、クラス内の run() メソッドを実行することを意味します。
何はともあれ、各スレッドで run() を実行する必要があります。
URL ごとにスレッドを作成し、start() メソッドを呼び出します。これにより、スレッド内で run() メソッドを実行するように CPU に指示されます。
すべてのスレッドの実行が完了するまでの時間を計算したいので、join() メソッドを呼び出します。
join() は、次の命令を実行する前に、このスレッドが終了するまで待機するようにメインスレッドに通知できます。
各スレッドで join() メソッドを呼び出したので、すべてのスレッドが実行を完了した後の実行時間を計算しました。

スレッドについて:

cpu は、start() を呼び出した直後に run() メソッドを実行しない場合があります。
異なるスレッド間での run() の実行順序を決定することはできません。
単一スレッドの場合、run() メソッド内のステートメントが順番に実行されることが保証されます。
これは、スレッド内の URL が最初にリクエストされ、その後返された結果が出力されるためです。

例 2

プログラムを使用してマルチスレッド間のリソース競合を実証し、この問題を解決します。

from threading import Thread
   
#define a global variable
some_var=0
   
classIncrementThread(Thread):
  defrun(self):
    #we want to read a global variable
    #and then increment it
    globalsome_var
    read_value=some_var
    print”some_var in %s is %d”%(self.name, read_value)
    some_var=read_value+1
    print”some_var in %s after increment is %d”%(self.name, some_var)
   
defuse_increment_thread():
  threads=[]
  foriinrange(50):
    t=IncrementThread()
    threads.append(t)
    t.start()
  fortinthreads:
    t.join()
  print”After 50 modifications, some_var should have become 50″
  print”After 50 modifications, some_var is %d”%(some_var,)
   
use_increment_thread()
ログイン後にコピー

このプログラムを複数回実行すると、さまざまな異なる結果が表示されます。
説明:
グローバル変数があり、すべてのスレッドがそれを変更しようとしています。
すべてのスレッドはこのグローバル変数を追加する必要があります 1 。
スレッド数が 50 の場合、最終値は 50 になるはずですが、実際はそうではありません。
なぜ50に達しなかったのですか?
some_var が 15 の場合、スレッド t1 は some_var を読み取ります。このとき、CPU は別のスレッド t2 に制御を渡します。
t2 スレッドによって読み取られた some_var も 15 です
t1 と t2 の両方で some_var が 16 に増加します
その時点で期待していたのは t1 でした t2 2 つのスレッドは some_var + を作成します 2 は 17 になります
ここでリソースの争奪戦が発生します。
他のスレッドでも同様の状況が発生する可能性があるため、最終結果は50未満になる可能性があります。
リソース競合の解決

from threading import Lock, Thread
lock=Lock()
some_var=0
   
classIncrementThread(Thread):
  defrun(self):
    #we want to read a global variable
    #and then increment it
    globalsome_var
    lock.acquire()
    read_value=some_var
    print”some_var in %s is %d”%(self.name, read_value)
    some_var=read_value+1
    print”some_var in %s after increment is %d”%(self.name, some_var)
    lock.release()
   
defuse_increment_thread():
  threads=[]
  foriinrange(50):
    t=IncrementThread()
    threads.append(t)
    t.start()
  fortinthreads:
    t.join()
  print”After 50 modifications, some_var should have become 50″
  print”After 50 modifications, some_var is %d”%(some_var,)
   
use_increment_thread()
ログイン後にコピー

このプログラムを再度実行すると、期待した結果が得られました。
説明:
ロック 競合状態を防ぐために使用されます
スレッド t1 が一部の操作を実行する前にロックを取得した場合。 t1 がロックを解放する前に、他のスレッドは同じ操作を実行しません
確認したいのは、スレッド t1 が some_var を読み取ると、t1 が some_var の変更を完了するまで他のスレッドは some_var を読み取ることができないということです
このように読んでください。そして、some_var の変更は論理的になりますアトミック操作。
例 3
例を使用して、あるスレッドが他のスレッドの変数 (非グローバル変数) に影響を与えることができないことを証明してみましょう。
time.sleep() はスレッドを一時停止し、スレッドの切り替えを強制的に実行できます。

from threading import Thread
import time
   
classCreateListThread(Thread):
  defrun(self):
    self.entries=[]
    foriinrange(10):
      time.sleep(1)
      self.entries.append(i)
    printself.entries
   
defuse_create_list_thread():
  foriinrange(3):
    t=CreateListThread()
    t.start()
   
use_create_list_thread()
ログイン後にコピー

何度か実行した後、期待していた結果が出力されないことがわかりました。 1 つのスレッドが印刷中に CPU が別のスレッドに切り替わるため、誤った結果が生成されます。必ず印刷する必要があります self.entries は、他のスレッドによる印刷の中断を防ぐための論理アトミック操作です。
Lock() を使用しました。以下の例を見てください。

from threading import Thread, Lock
import time
   
lock=Lock()
   
classCreateListThread(Thread):
  defrun(self):
    self.entries=[]
    foriinrange(10):
      time.sleep(1)
      self.entries.append(i)
    lock.acquire()
    printself.entries
    lock.release()
   
defuse_create_list_thread():
  foriinrange(3):
    t=CreateListThread()
    t.start()
   
use_create_list_thread()
ログイン後にコピー

今度は正しい結果が見られました。これは、あるスレッドが他のスレッドの内部変数 (非グローバル変数) を変更できないことを証明しています。

上記は Python のマルチスレッドです。その他の関連記事については、PHP 中国語 Web サイト (www.php.cn) に注目してください。


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート