Python開発の道(十)

6219 ワード

二、同時プログラミングの――スレッド
スレッドとは?各プロセスには、少なくとも1つのスレッドがあります.私たちが授業を受けて先生の講義を聞くように、耳だけでなく、頭も考えなければならない.1つのプログラムが実行中にプロセスしかない場合、ブロックに遭遇するとプログラムは実行できません.では、どのようにしてスレッドを開きますか?上のコード:
import time
from threading import Thread
def func(i):
    time.sleep(1)

Thread(target=func,args=(1,)).start()

1.スレッドの特徴
1)プロセスごとに少なくとも1つのプライマリ・スレッドがコードの実行を担当します.
2)メインスレッドで新しいスレッドを開くことができる
3)同じプロセスで2つのスレッドが同時に動作する
4)スレッドこそCPUスケジューリングの最小単位
5)複数のスレッド間のデータは共有されている
6)マルチスレッド処理による高計算型シーンPythonは問題ない
7)一つのプロセスで同じ時間にCPUにアクセスできるスレッドは一つしかない
注意:Pythonコードの実行は、Python仮想マシン(解釈器メインサイクルとも呼ばれる)によって制御されます.Pythonは設計当初から主サイクルで実行するスレッドが1つしかないことを考慮していた.Pythonインタプリタでは複数のスレッドを「実行」できますが、任意の時点で1つのスレッドだけがインタプリタで実行されます.Python仮想マシンへのアクセスは、グローバル解釈ロック(GIL)によって制御されます.このロックこそ、同じ時点で1つのスレッドだけが実行されることを保証します.
2.デーモンスレッド
デーモンスレッドとは?プロセスの理屈と同じように、プライマリ・スレッドが終了するとデーモン・スレッドも同時に終了し、デーモン・スレッドはプライマリ・スレッドが完全に終了するまで待機します.
3.ロック
1)デッドロック
デッドロックとは?2つ以上のプロセスまたはスレッドが実行中にリソースを争うことによって互いに待つ現象であり、外力の作用がなければ推進できない.このとき、システムがデッドロック状態にあるか、システムがデッドロックを発生していると呼ばれ、これらが永遠に互いに待っているプロセスをデッドロックプロセスと呼ぶ.次のコードはデッドロック現象を発生します.
from threading import Lock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

解決策は、Pythonで同じスレッドで同じリソースを複数回要求することをサポートするために、Pythonは再ロック可能なRLockを提供する再帰ロックである.このRLock内部メンテナはロックとcounter変数であり、counterはacquireの回数を記録し、リソースを複数回requireすることができる.1つの県城のすべてのacquireがreleaseされるまで、他のスレッドは資源を得ることができます.上記の例ではロックの代わりにRLockを使用するとデッドロックは発生しません.次のようになります.
from threading import RLock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

4.信号量
プロセスと同様に、Semaphoreは内蔵カウンタを管理し、例えばsemaphoreを得るには5つのスレッドしかない.すなわち、最大接続数を5に制限することができる.
5.イベント
プロセスと同じ
event.isSet():eventのステータス値を返します.
event.wait():event.isSet()=Falseはスレッドをブロックします.
event.set():eventの状態値をTrueに設定し、すべてのブロックプールのスレッドがアクティブ化され、オペレーティングシステムのスケジューリングを待つ.
event.clear():回復eventの状態値はFalseです.
6.スレッドプール
プロセスプールと同じように、もし私たちが忙しいときに何百万もの任務を走る必要があるならば、暇な時にはわずかな任務しかないかもしれません.では、何百万ものタスクが実行される必要がある場合、何千万ものプロセス/スレッドを作成する必要がありますか?まず、作成プロセスにしてもスレッドにしても時間がかかり、破棄プロセス/スレッドにしても時間がかかります.また、何百万ものプロセスが作成されても、オペレーティングシステムは同時に実行させることができません.これは、逆にプログラムの効率に影響します.したがって、タスクに基づいてプロセス/スレッドをオンまたは終了することは制限されません.次は簡単な池です.
import time
from concurrent.futures import ThreadPoolExecutor
def func(num):
    time.sleep(1)
    print(num)

t= ThreadPoolExecutor(20)
for i in range(100):
    t.submit(func,i)
t.shutdown()          # join     

この池には20個のスレッドが置いてあり、使い勝手に取り、使い終わったら戻します.これにより、実行効率が大幅に向上します.
例:マルチスレッドWebページのトレースをシミュレートする
import time
import random
from concurrent.futures import ThreadPoolExecutor

urls = [
    'www.baidu.com',
    'www.sogou.com',
    'www.sohu.com',
    'www.sina.com',
    'www.163.com',
    'www.python.org',

]

def analies(content):
    print('    ')
    print(content.result())

def get_url(url):
    time.sleep(random.uniform(1,3))
    return url*10

t = ThreadPoolExecutor(3)
for url in urls:
    t.submit(get_url,url).add_done_callback(analies)