python3クイックスタート(9) - のpython3並行プログラミング

python3クイックスタート(9) - のpython3並行プログラミング

、Pythonのスレッドモジュール

1.はじめスレッド

スレッドIDによって標準スレッドは、現在の命令ポインタ(PC)は、設定され、スタック構成要素レジスタ。スレッドは、独立したスケジューリングとディスパッチシステムの基本的な単位であり、他のすべてのスレッドは、プロセス内のプロセス・リソースを共有すると、スレッド自体がシステムリソースを持っていない、物理的プロセスです。プロセスは、少なくとも一つのねじ山を有しており、プログラムのエントリ、すなわちメインスレッド、ワークスレッドと呼ばれる別のスレッドとして。
     マルチスレッドは、ソフトウェアやハードウェアから複数のスレッド技術の同時実行を実現するために参照します。ハードウェアサポートへのコンピュータのマルチスレッド機能をサポートし、それによって全体の処理性能を向上させる、同時に複数のスレッドを実行することが可能です。

2、スレッドの状態

三つの基本的な状態を実行し、ブロックする準備ができてスレッドがあります。準備完了状態は、すべての条件がスレッドがCPUで実行待ち、実行していることを意味し、実行している状態は、スレッドはCPUが実行されている所有指し、イベント・ロジックで待機している状態が実行可能ではないスレッドをブロック。
三つの状態の相互変換下図のように:
python3クイックスタート(9) - のpython3並行プログラミング

図2に示すように、スレッドのスレッド・モジュール

python3 _threadスレッドのサポートを提供し、2つのモジュールスレッディング。
_threadこれは、スレッド・モジュールを放棄されているスレッドモジュール限られた機能、互換性のサポートプログラムに比べて、低レベル、原糸ロックと簡単に提供します。
スレッド・モジュールに加えて含む_thread。また、提供されるすべてのメソッドのモジュールを、方法
threading.currentThreadを():現在のスレッドの変数を返します。
threading.enumerateは():実行中のスレッドのリストを返します。実行を開始、終了する前に、それは開始前と終了後に糸が含まれていないスレッドを指します。
threading.activeCountは():実行中のスレッドの数を返し、とlen(threading.enumerate())と同じ結果を持っています。
次のようにスレッドクラスが提供されます。
RUN():図スレッド活動の方法。
開始():スレッドの活動を開始。
([時間])参加:スレッドが中断されるまで待ちます。スレッドのjoin()メソッドまで、呼び出し元のスレッドをブロックするサスペンションと呼ばれている-通常の終了または未処理の例外を投げる-またはオプションのタイムアウトが発生します。
isAliveは():スレッドがアクティブで返します。
getName():スレッド名を返します。
setName():スレッド名を設定します。

3、マルチプロセッシングモジュール

マルチプロセッシングモジュールは、マルチプロセスモジュールのクロスプラットフォームのバージョンであるProcessクラスは、プロセスオブジェクトを表しています。あなたは子プロセスを作成する場合は、あなただけがプロセスのインスタンスを作成するための機能や機能を実行するためのパラメータを渡す必要があります。
Process(self,group=None,target=None,name=None,args=(),kwargs=())
グループのパラメータは、値は常にNoneです、使用されていません。
タスクを実行するための呼び出し、子プロセスを表すオブジェクトをターゲットにしています。
名前は、子プロセスとして命名することができます。
引数=(「monicx」):引数接合のような、タプルの形態である、コンマが存在する必要があり、位置パラメータの目標伝達関数を指定
kwargsからターゲットノード指定されたキーワードパラメータ転送機能、例えばkwargsからの=として辞書、{[名「:」monicx「」年齢「:} 18は、
次のようにプロセスは、
プロセスを開始し、子プロセスのrun()メソッドを呼び出します()を起動します。
()を実行します。プロセスは、メソッド呼び出しの対象指定された機能に実行を開始し、子クラスは、実行中のrunメソッドを実装する必要があります。
終了():プロセスが子プロセスを作成した場合、子プロセスがゾンビプロセスになります任意の清掃作業を行わないであろう、プロセスを強制終了する。プロセスはまた、ロックを保持している場合、ロックがデッドロックにつながった、プロセスを解放しません。
is_alive():プロセスは「生きている」状態であるかどうかを判断します。
(タイムアウト)参加:プロセスはメインプロセスの実行を継続する前に完了するための主要なプロセスの子プロセスを待つことをしてみましょう。タイムアウトは、オプションのタイムアウトでは、複数の時間はメインコースを待ちません。

4、グローバルインタプリタロックGIL

Pythonは真の意味でのマルチスレッドをサポートしていません。Pythonモジュールは、マルチスレッド、マルチスレッド提供していますが、コードの速度を上げたい場合はマルチスレッドモジュールの使用を推奨していません。Pythonはグローバルインタープリタロック(GIL)は、世界的なロックがいつでも複数のスレッドが、一つだけが実行されることを保証する世界的なロックを持っています。スレッドの実行速度が非常に高速です、あなたはスレッドが並列に実行されていると思うが、実際に実行するために交代します。GIL処理後のスレッドの実行のコストが増加します。
グローバルロックGIL(グローバルインタプリタロック)はPythonの機能ではなく、Pythonのパーサ(CPythonと)の実装時の概念が導入されました。Pythonは何GILをJPythonのないCPythonと、PyPy、サイコ、こうした異なるPythonの実行環境としては、持っています。CPythonのは、ほとんどの環境Pythonの実行環境の下で、デフォルトで、GILは、PythonはGILに頼ることができない、Pythonの機能ではありません。
GILは、同じ時間を制限し、一つのスレッドだけが実行されている、あなたは、マルチコアCPUを利用することはできません。GILは、同じ時間内でのデータの共有を制御するためにのみ、従ってデータのセキュリティを確保し、タスクによって改変することができる、すべてのシリアルなり、同時に実行され、本質的にミューテックスです。プロセスにPythonは、他のスレッドメインChengkaiチーからメインスレッドまたはスレッドのレベル、ならびにインタプリタは、ガベージコレクションの説明になっているだけでなく。コードデータの種類は、すべてのスレッドによって共有されるようなプロセスでは、すべてのデータは、共有されている複数のスレッドが最初のアクセス権を取得するために実行されるインタプリタコードにアクセスし、ターゲット・コード・インタプリタコードに実行するために、インタプリタ・コードは、すべてのスレッドで共有されているので、ガベージコレクタスレッドはまた、すなわち、GILをハンドルをロックするデータセキュリティの必要性を確保するためにして、離れた通訳のコード実行にアクセスすることができます。
GIL、唯一つのスレッドが実行され、同じ時間に同じプロセスのため。マルチコアCPUは、並列コンピューティングで行うことができるので、マルチコア・コンピューティング・パフォーマンスを向上させることができますが、CPU I / Oブロックの場合には、まだそのI / O集中型のタスクにマルチコアCPUが明らかにされていません、待つ必要があります。ミッションをよれば、計算集約的であるか、またはI / O集約、計算集約的なタスク、集中的なI / O、マルチスレッドドミナントため支配マルチプロセスのために、異なる方法を用いて異なるシナリオ。
計算集約型のタスク-マルチプロセス・ソリューション:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time

def work():
    result = 0
    for x in range(100000000):
        result *= x

if __name__ == "__main__":
    processes = []
    print("CPU: ", os.cpu_count())
    start = time.time()
    for i in range(4):
        p = Process(target=work)
        processes.append(p)
        p.start()
    for p in processes:
        p.join()
    end = time.time()
    print("计算密集型任务,多进程耗时 %s" % (end - start))

# output:
# CPU:  4
# 计算密集型任务,多进程耗时 9.485123872756958

計算集約型のタスク - マルチスレッドのシナリオ:

# -*- coding:utf-8 -*-
from threading import Thread
import os, time

def work():
    res = 0
    for x in range(100000000):
        res *= x

if __name__ == "__main__":
    threads = []
    print("CPU: ",os.cpu_count())
    start = time.time()
    for i in range(4):
        thread = Thread(target=work)  # 多进程
        threads.append(thread)
        thread.start()
    for thread in threads:
        thread.join()
    end = time.time()
    print("计算密集型任务,多线程耗时 %s" % (end - start))

# output:
# CPU:  4
# 计算密集型任务,多线程耗时 18.434288501739502

IO集約型のタスク - マルチプロセス・ソリューション:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import os, time

def work():
    time.sleep(2)
    print("hello,Python----------------------------------------------------", file=open("tmp.txt", "w"))

if __name__ == "__main__":
    processes = []
    print("CPU: ", os.cpu_count())
    start = time.time()
    for i in range(400):
        p = Process(target=work)  # 多进程
        processes.append(p)
        p.start()
    for p in processes:
        p.join()
    stop = time.time()
    print("I/0密集型任务,多进程耗时 %s" % (stop - start))

# output:
# CPU:  4
# I/0密集型任务,多进程耗时 2.8894519805908203

IO集約型のタスク - マルチスレッドのシナリオ:

# -*- coding:utf-8 -*-
from threading import Thread
import os, time

def work():
    time.sleep(2)
    print("hello,Python----------------------------------------------------", file=open("tmp.txt", "w"))

if __name__ == "__main__":
    threads = []
    print("CPU: ", os.cpu_count())
    start = time.time()

    for x in range(400):
        thread = Thread(target=work)
        threads.append(thread)
        thread.start()
    for thread in threads:
        thread.join()
    end = time.time()
    print("IO密集型任务,多线程耗时 %s" % (end - start))

# output:
# CPU:  4
# IO密集型任务,多线程耗时 2.044438362121582

第二に、スレッドを作成

1、threading.Threadインスタンス化

threading.Threadコンストラクタ次のように:

def __init__(self, group=None, target=None, name=None,
             args=(), kwargs=None, *, daemon=None):

そのstart()メソッドを呼び出すと、threading.Threadインスタンスを作成します。

# -*- coding:utf-8 -*-
import time
import threading

def work_task(counter):
    print("%s %s" % (threading.current_thread().name, time.ctime(time.time())))
    n = counter;
    while n > 0:
        time.sleep(1)
        n -= 1

if __name__ == "__main__":
    print("main thread start:", time.strftime("%Y-%m-%d %H:%M:%S"))

    threads = []
    for x in range(10):
        thread = threading.Thread(target=work_task, args=(x, ))
        threads.append(thread)

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()

    print("main thread end:", time.strftime("%Y-%m-%d %H:%M:%S"))

# output:
# main thread start: 2019-07-03 21:49:58
# Thread-1 Wed Jul  3 21:49:58 2019
# Thread-2 Wed Jul  3 21:49:58 2019
# Thread-3 Wed Jul  3 21:49:58 2019
# Thread-4 Wed Jul  3 21:49:58 2019
# Thread-5 Wed Jul  3 21:49:58 2019
# Thread-6 Wed Jul  3 21:49:58 2019
# Thread-7 Wed Jul  3 21:49:58 2019
# Thread-8 Wed Jul  3 21:49:58 2019
# Thread-9 Wed Jul  3 21:49:58 2019
# Thread-10 Wed Jul  3 21:49:58 2019
# main thread end: 2019-07-03 21:50:07

2、threading.Thread子スレッド

サブクラスでは、threading.Threadクラスの継承から直接新しいサブクラスを作成することにより、新しいスレッド、雌ねじスタート関数呼び出しを開始するために、実行()とinit()メソッド、インスタンス化された通話開始()メソッドをオーバーライド()メソッドを実行します。

# -*- coding:utf-8 -*-
import threading
import time

class WorkThread(threading.Thread):
    def __init__(self, thread_id, name):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.name = name

    def run(self):
        print("start thread: ", self.name)
        work(self.name, self.thread_id)
        print("end thread: ", self.name)

def work(thread_name, thread_id):
    print("%s %s %s" % (thread_name, thread_id, time.ctime(time.time())))
    i = 0;
    while i < 2:
        i += 1
        time.sleep(1)

if __name__ == '__main__':
    thread1 = WorkThread(1, "Thread1")
    thread2 = WorkThread(2, "Thread2")

    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()

    print("exit main thread")

# output:
# start thread:  Thread1
# Thread1 1 Tue Jul  2 20:39:42 2019
# start thread:  Thread2
# Thread2 2 Tue Jul  2 20:39:42 2019
# end thread:  end thread: Thread1
#  Thread2
# exit main thread

必要性は外部から機能を渡す場合は、インスタンスは、子スレッド、例の方法では、実行コールを属性引数として渡すことができます。
ターゲット= self.target
self.args =引数

# -*- coding:utf-8 -*-
import threading
import time

class WorkThread(threading.Thread):
    def __init__(self, target, args):
        threading.Thread.__init__(self)
        self.target = target
        self.args = args

    def run(self):
        print("start thread: ", self.name)
        self.target(*self.args)
        print("end thread: ", self.name)

def work_task(counter):
    time.sleep(1)
    print("%s %s" % (threading.currentThread().name, time.ctime(time.time())))
    i = counter;
    while i > 0:
        i -= 1

if __name__ == '__main__':
    print("main thread start:", time.strftime("%Y-%m-%d %H:%M:%S"))

    threads = []
    for x in range(10):
        thread = threading.Thread(target=work_task, args=(x,))
        threads.append(thread)

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()

    print("main thread end:", time.strftime("%Y-%m-%d %H:%M:%S"))

# output:
# main thread start: 2019-07-03 22:02:32
# Thread-1 Wed Jul  3 22:02:33 2019Thread-5 Wed Jul  3 22:02:33 2019
# Thread-2 Wed Jul  3 22:02:33 2019
# Thread-3 Wed Jul  3 22:02:33 2019
# Thread-4 Wed Jul  3 22:02:33 2019
#
# Thread-7 Wed Jul  3 22:02:33 2019Thread-6 Wed Jul  3 22:02:33 2019
# Thread-10 Wed Jul  3 22:02:33 2019
# Thread-8 Wed Jul  3 22:02:33 2019
#
# Thread-9 Wed Jul  3 22:02:33 2019
# main thread end: 2019-07-03 22:02:33

3、起動して実行します

import threading
import time

def work_task(counter):
    n = counter
    while n > 0:
        n -= 1
        print("thread name: %s, id: %s" % (threading.currentThread().name, threading.currentThread().ident))

if __name__ == "__main__":
    print("main thread start")
    thread1 = threading.Thread(target=work_task, args=(5,))
    thread2 = threading.Thread(target=work_task, args=(5,))
    thread1.start()
    thread2.start()

    print("main thread end")

# output:
# main thread start
# thread name: Thread-1, id: 139926959064832thread name: Thread-2, id: 139926880384768main thread end
#
#
# thread name: Thread-1, id: 139926959064832
# thread name: Thread-2, id: 139926880384768thread name: Thread-1, id: 139926959064832
#
# thread name: Thread-1, id: 139926959064832
# thread name: Thread-2, id: 139926880384768thread name: Thread-1, id: 139926959064832
#
# thread name: Thread-2, id: 139926880384768
# thread name: Thread-2, id: 139926880384768

2つの新しいサブスレッドを交互に実行開始するstart()メソッドを使用して、それぞれの子プロセスIDが異なる、スレッド名が定義され、スレッドオブジェクト=「XXXX」の値に設定名で開始し、名前のないパラメータの値であればスレッド-xは、システムによって割り当てられた名前を表示します。

import threading
import time

def work_task(counter):
    n = counter
    while n > 0:
        n -= 1
        print("thread name: %s, id: %s" % (threading.currentThread().name, threading.currentThread().ident))

if __name__ == "__main__":
    print("main thread start")
    thread1 = threading.Thread(target=work_task, args=(5,))
    thread2 = threading.Thread(target=work_task, args=(5,))
    thread1.run()
    thread2.run()

    print("main thread end")

# output:
# main thread start
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# thread name: MainThread, id: 140683421988672
# main thread end

run()メソッドは、スレッドを開始すると、スレッド名が印刷されMainThreadは、それがメインスレッドです。両方のスレッド()のみ(thread2.run順次実行する実行した後、)実行で開始するが、(thread1.run実行する方法)は、2つのスレッドが、従って、新しいスレッドを開始しないで、メインスレッドで動作しますrun()メソッドは、単に通常の関数呼び出しです。

図4に示すように、この方法に参加

処理が開始されると、スレッドが複数のスレッドを設定する際に、メインスレッドが複数の子スレッドを作成し、プログラム実行フローの最小単位であるため、それはデフォルトのメインスレッドを生成します。Pythonでは、その任務を実施した後、メインスレッドは、それが彼らのタスクが完了するまで、子スレッドがそのタスクを実行していきます、デフォルトを終了します。

import threading
import time

def work_task(counter):
    n = counter
    while n > 0:
        n -= 1
        print("thread name: %s, id: %s" % (threading.currentThread().name, threading.currentThread().ident))

if __name__ == "__main__":
    print("main thread start")
    threads = []
    for x in range(5):
        thread = threading.Thread(target=work_task, args=(5,))
        threads.append(thread)
    for thread in threads:
        thread.start()

    print("main thread end")

# output:
# main thread start
# thread name: Thread-1, id: 140306042726144thread name: Thread-2, id: 140306034333440
# thread name: Thread-2, id: 140306034333440
# thread name: Thread-2, id: 140306034333440
# thread name: Thread-2, id: 140306034333440
# thread name: Thread-2, id: 140306034333440
# thread name: Thread-3, id: 140306025940736
#
# thread name: Thread-3, id: 140306025940736
# thread name: Thread-3, id: 140306025940736
# thread name: Thread-1, id: 140306042726144thread name: Thread-3, id: 140306025940736
# thread name: Thread-3, id: 140306025940736
#
# thread name: Thread-1, id: 140306042726144
# thread name: Thread-1, id: 140306042726144
# thread name: Thread-1, id: 140306042726144
# thread name: Thread-4, id: 140306034333440
# thread name: Thread-4, id: 140306034333440
# thread name: Thread-5, id: 140306042726144thread name: Thread-4, id: 140306034333440
# main thread endthread name: Thread-4, id: 140306034333440
# thread name: Thread-4, id: 140306034333440
#
# thread name: Thread-5, id: 140306042726144
#
# thread name: Thread-5, id: 140306042726144
# thread name: Thread-5, id: 140306042726144
# thread name: Thread-5, id: 140306042726144

実行が完了すると、スレッドが完全に終わりを実装していない子があるかもしれデーモンスレッドとしてとき、子スレッドの設定タスクは、setdaemon(true)メソッド、メインスレッドは、スレッド全体をすべて実行終了され、それは停止を余儀なくされました。setdaemonがプロモータースレッドの前に設定する必要があります設定します。

import threading
import time

def work_task(counter):
    n = counter
    time.sleep(1)
    while n > 0:
        n -= 1
        print("thread name: %s, id: %s" % (threading.currentThread().name, threading.currentThread().ident))

if __name__ == "__main__":
    print("main thread start")
    threads = []
    for x in range(5):
        thread = threading.Thread(target=work_task, args=(5,))
        threads.append(thread)
    for thread in threads:
        thread.setDaemon(True)
        thread.start()

    print("main thread end")

# output:
# main thread start
# main thread end

サブラインを実行するためのメインスレッドが待機を結合するために使用される方法の後に、その結​​果を返し、その後、コンテンツの残りの部分を実行するためにメインスレッドは、子スレッドが実行を完了していない、メインスレッドは、状態を待っています。

import threading
import time

def work_task(counter):
    n = counter
    time.sleep(1)
    while n > 0:
        n -= 1
        print("thread name: %s" % threading.currentThread().name)

if __name__ == "__main__":
    print("main thread start")
    threads = []
    for x in range(5):
        thread = threading.Thread(target=work_task, args=(5,))
        threads.append(thread)
    for thread in threads:
        thread.setDaemon(True)
        thread.start()
        thread.join()

    print("main thread end")

# output:
# main thread start
# thread name: Thread-1
# thread name: Thread-1
# thread name: Thread-1
# thread name: Thread-1
# thread name: Thread-1
# thread name: Thread-2
# thread name: Thread-2
# thread name: Thread-2
# thread name: Thread-2
# thread name: Thread-2
# thread name: Thread-3
# thread name: Thread-3
# thread name: Thread-3
# thread name: Thread-3
# thread name: Thread-3
# thread name: Thread-4
# thread name: Thread-4
# thread name: Thread-4
# thread name: Thread-4
# thread name: Thread-4
# thread name: Thread-5
# thread name: Thread-5
# thread name: Thread-5
# thread name: Thread-5
# thread name: Thread-5
# main thread end

timeoutパラメータに参加し、デーモンスレッドを設定すると、チェンDuiziメインスレッドが待機時間をタイムアウト、タイムアウト時間をスレッドそれぞれの子を与え、子スレッドの実行を聞かせて、時間に関係なく、タスクが完了していない、直接殺す、アップではありません。複数の子スレッド場合は、すべてのは、それぞれの子スレッドのタイムアウトや蓄積のための時間を待っています。

import threading
import time

def work_task(counter):
    print("thread name: %s work task start" % threading.currentThread().name)
    n = counter
    time.sleep(4)
    while n > 0:
        n -= 1
    else:
        print("thread name: %s work task end" % threading.currentThread().name)

if __name__ == "__main__":
    print("main thread start")
    threads = []
    for x in range(5):
        thread = threading.Thread(target=work_task, args=(5,))
        threads.append(thread)

    for x in range(5):
        threads[x].setDaemon(True)
        threads[x].start()
        threads[x].join(1)

    print("main thread end")

# output:
# main thread start
# thread name: Thread-1 work task start
# thread name: Thread-2 work task start
# thread name: Thread-3 work task start
# thread name: Thread-4 work task start
# thread name: Thread-5 work task start
# thread name: Thread-1 work task end
# main thread end

デーモンスレッドを設定していない場合は、メインスレッドは、一定時間待機し、タイムアウトを蓄積し、時間がアップしている、メインスレッドの終了が、子スレッドを殺していない、子スレッドは、まだすべての子スレッドが終了するまで継続することができ、プログラムは終了します。

import threading
import time

def work_task(counter):
    print("thread name: %s work task start" % threading.currentThread().name)
    n = counter
    time.sleep(4)
    while n > 0:
        n -= 1
    else:
        print("thread name: %s work task end" % threading.currentThread().name)

if __name__ == "__main__":
    print("main thread start")
    threads = []
    for x in range(5):
        thread = threading.Thread(target=work_task, args=(5,))
        threads.append(thread)

    for x in range(5):
        threads[x].start()
        threads[x].join(1)

    print("main thread end")

# output:
# main thread start
# thread name: Thread-1 work task start
# thread name: Thread-2 work task start
# thread name: Thread-3 work task start
# thread name: Thread-4 work task start
# thread name: Thread-5 work task start
# thread name: Thread-1 work task end
# main thread end
# thread name: Thread-2 work task end
# thread name: Thread-3 work task end
# thread name: Thread-4 work task end
# thread name: Thread-5 work task end

第三に、スレッドの同期

共通データ変更の複数のスレッドが、予期しない結果が発生する可能性がある場合、データの正確性を確保するために、複数のスレッドの必要性が同期します。

1、ミューテックス

ロックthreading.Threadクラスロックおよびロックが単にRLOCKスレッドの同期を実現することができ、RLOCKロックロックロック取得方法及び解放方法の両方が、一つだけスレッドデータ操作は、取得の間に配置された操作方法を解放する必要がある可能。

# -*- coding:utf-8 -*-
import threading
import time

class WorkThread(threading.Thread):
    def __init__(self, thread_id, name):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.name = name

    def run(self):
        thread_locker.acquire()
        print("start thread: ", self.name)
        work(self.name, self.thread_id)
        print("end thread: ", self.name)
        thread_locker.release()

def work(thread_name, thread_id):
    print("%s %s %s" % (thread_name, thread_id, time.ctime(time.time())))
    i = 0;
    while i < 2:
        i += 1
        time.sleep(1)

thread_locker = threading.Lock()
threads = []

if __name__ == '__main__':
    thread1 = WorkThread(1, "Thread1")
    thread2 = WorkThread(2, "Thread2")

    thread1.start()
    thread2.start()

    threads.append(thread1)
    threads.append(thread2)

    for t in threads:
        t.join()

    print("exit main thread")

# output:
# start thread:  Thread1
# Thread1 1 Tue Jul  2 20:48:05 2019
# end thread:  Thread1
# start thread:  Thread2
# Thread2 2 Tue Jul  2 20:48:07 2019
# end thread:  Thread2
# exit main thread

2、セマフォ

ミューテックスのスレッドの一定数が共有データにアクセス可能にしながら、後者は唯一の誰かの前で待つことができ、5人が業務を遂行するために許可されている一方で、5つの窓があり、このような銀行のカウンターとして、セマフォながら、共有データへの一つのスレッドだけのアクセスを可能にしながら、事業終了後にカウンタを入力することができます。

# -*- coding:utf-8 -*-
import threading
import time

semaphore = threading.BoundedSemaphore(5)
threads = []

def do_work(name):
    semaphore.acquire()
    time.sleep(2)
    print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {threading.currentThread().name} is carrying on business")
    semaphore.release()

if __name__ == '__main__':
    print("main thread start:", time.strftime("%Y-%m-%d %H:%M:%S"))

    for i in range(10):
        t = threading.Thread(target=do_work, args=(i,))
        threads.append(t)

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()

    print("main thread end:", time.strftime("%Y-%m-%d %H:%M:%S"))

# output:
# main thread start: 2019-07-03 22:31:06
# 2019-07-03 22:31:08 Thread-1 is carrying on business
# 2019-07-03 22:31:08 Thread-3 is carrying on business
# 2019-07-03 22:31:08 Thread-2 is carrying on business
# 2019-07-03 22:31:08 Thread-4 is carrying on business
# 2019-07-03 22:31:08 Thread-5 is carrying on business
# 2019-07-03 22:31:10 Thread-6 is carrying on business
# 2019-07-03 22:31:10 Thread-7 is carrying on business
# 2019-07-03 22:31:10 Thread-9 is carrying on business
# 2019-07-03 22:31:10 Thread-8 is carrying on business
# 2019-07-03 22:31:10 Thread-10 is carrying on business
# main thread end: 2019-07-03 22:31:10

3、条件変数

条件変数は、他のスレッドBを待って、通知後にスレッドを停止することができ、スレッドBは、条件(通知)スレッド実行を継続を満たします。条件は実行のスレッドを満たしている場合、また、スレッドを待機する他の状態を通知することができる、スレッドが最初の条件が満たされていない場合、スレッド待機(WAIT)とがロック状態変数を解放し、ロック状態変数を得ます。通知を受けた後、待機状態にある他のスレッドが条件を再審査されます。

import threading
import time

class ThreadA(threading.Thread):
    def __init__(self, con, name):
        super(ThreadA, self).__init__()
        self.cond = con
        self.name = name

    def run(self):
        self.cond.acquire()
        print(self.name + ": What can I do for you?")
        self.cond.notify()
        self.cond.wait()
        print(self.name + ": Five yuan.")
        self.cond.notify()
        self.cond.wait()
        print(self.name + ": You are welcome.")
        self.cond.release()

class ThreadB(threading.Thread):
    def __init__(self, con, name):
        super(ThreadB, self).__init__()
        self.cond = con
        self.name = name

    def run(self):
        self.cond.acquire()
        time.sleep(1)
        print(self.name + ": A hot dog, please!")
        self.cond.notify()
        self.cond.wait()
        print(self.name + ": Thanks.")
        self.cond.notify()
        self.cond.release()

if __name__ == "__main__":
    cond = threading.Condition()
    thread1 = ThreadA(cond, "ThreadA")
    thread2 = ThreadB(cond, "ThreadB")
    thread1.start()
    thread2.start()

# output:
# ThreadA: What can I do for you?
# ThreadB: A hot dog, please!
# ThreadA: Five yuan.
# ThreadB: Thanks.
# ThreadA: You are welcome.

4つのイベント

スレッド間通信のためのイベント。スレッドは、他の1つまたは複数のスレッドは、スレッドのみ起こされるのを、他のスレッド設定するまでブロックされ、方法は、イベントオブジェクトを呼び出し待機、待って、信号を送信します。

import threading
import time

class ThreadA(threading.Thread):
    def __init__(self, _event, name):
        super(ThreadA, self).__init__()
        self.event = _event
        self.name = name

    def run(self):
        print(self.name + ": What can I do for you?")
        self.event.set()
        time.sleep(0.5)
        self.event.wait()
        print(self.name + ": Five yuan.")
        self.event.set()
        time.sleep(0.5)
        self.event.wait()
        self.event.clear()
        print(self.name + ": You are welcome!")

class ThreadB(threading.Thread):
    def __init__(self, _event, name):
        super(ThreadB, self).__init__()
        self.event = _event
        self.name = name

    def run(self):
        self.event.wait()
        self.event.clear()
        print(self.name + ": A hot dog, please!")
        self.event.set()
        time.sleep(0.5)
        self.event.wait()
        print(self.name + ": Thanks!")
        self.event.set()

if __name__ == "__main__":
    event = threading.Event()
    thread1 = ThreadA(event, "ThreadA")
    thread2 = ThreadB(event, "ThreadB")
    thread1.start()
    thread2.start()

# output:
# ThreadA: What can I do for you?
# ThreadB: A hot dog, please!
# ThreadA: Five yuan.
# ThreadB: Thanks!
# ThreadA: You are welcome!

5、スレッドプライオリティキュー

Pythonのキューモジュールは、FIFOキューのキュー(先入れ先出し)には、LIFO(最初に出て、内の最後の)キューLifoQueue、優先キュー優先度つきキューを含む、同期キューベースのスレッドセーフを提供します。
キュー、LifoQueue、優先度つきキューを達成しているロックプリミティブを複数のスレッドに直接使用することができ、キューは、スレッド間の同期を達成するために使用することができます。
キューモジュールの一般的な方法:
Queue.qsize()キューのサイズを返し
、キューが空の場合、)Queue.emptyを(Trueを返し、そうでなければFalseを返す
Queue.fullを()キューがいっぱいの場合、Trueを返し、そうでない場合はFalseを返す
Queue.getを([ブロック[タイムアウト]])買収キュー、タイムアウト待ち時間
Queue.get_nowait()むしろQueue.get(偽)
Queue.put(項目)キュー、タイムアウト待ち時間書き込み
Queue.putむしろQueue.put_nowait(項目) (項目、偽)
Queue.task_done()タスクに信号を送信するジョブ、Queue.task_done()関数の完了は、キュー完了した後
、キューが空になるまで、その後、他の操作を実行Queue.join()ブロック

# -*- coding:utf-8 -*-
import threading
import time
import queue

exitFlag = 0

class WorkThread(threading.Thread):
    def __init__(self, id, name, q):
        threading.Thread.__init__(self)
        self.thread_id = id
        self.name = name
        self.queue = q

    def run(self):
        work(self.name, self.queue)

def work(thread_name, q):
    while not exitFlag:
        thread_locker.acquire()
        if not work_queue.empty():
            data = q.get()
            print("%s processing %s" % (thread_name, data))
            thread_locker.release()
        else:
            thread_locker.release()
        time.sleep(1)

thread_locker = threading.Lock()
thread_list = ["Thread1", "Thread2", "Thread3"]
work_queue = queue.Queue(10)
messages = ["one", "two", "three", "four", "five"]
threads = []
thread_id = 1

if __name__ == '__main__':
    # 创建新线程
    for name in thread_list:
        thread = WorkThread(thread_id, name, work_queue)
        thread.start()
        threads.append(thread)
        thread_id += 1

    # 填充队列
    thread_locker.acquire()
    for word in messages:
        work_queue.put(word)
    thread_locker.release()

    # 等待队列清空
    while not work_queue.empty():
        pass

    # 通知线程是时候退出
    exitFlag = 1

    # 等待所有线程完成
    for t in threads:
        t.join()
    print("exit main thread")

# output:
# Thread1 processing one
# Thread3 processing two
# Thread2 processing three
# Thread1 processing four
# Thread3 processing five
# exit main thread

6、スレッドのデッドロック

デッドロックは、実装プロセスに2つの以上のプロセスまたはスレッド、お互いを待っによって引き起こされるリソースの競合の結果の現象です。スレッド間で共有する場合、複数のリソースの所有は、リソースの一部であったと同時に、互いのリソースを待っているならば、それはデッドロックになります。データベース、例えば、スレッド演算結果Bが操作されたスレッドする必要があり、結果はA、Bがスレッド転帰の間作動されていない場合、スレッドは、動作Bではスレッド必要があり、ケースA、Bのスレッドには常に他の状態の終了を待っています。

import time
import threading

class Account:
    def __init__(self, _id, balance, lock):
        self.id = _id
        self.balance = balance
        self.lock = lock

    def withdraw(self, amount):
        self.balance -= amount

    def deposit(self, amount):
        self.balance += amount

def transfer(_from, to, amount):
    if _from.lock.acquire():
        _from.withdraw(amount)
        time.sleep(1)
        print('wait for lock...')
        if to.lock.acquire():
            to.deposit(amount)
            to.lock.release()
        _from.lock.release()
    print('finish...')

if __name__ == "__main__":
    a = Account('a', 1000, threading.Lock())
    b = Account('b', 1000, threading.Lock())
    threading.Thread(target=transfer, args=(a, b, 100)).start()
    threading.Thread(target=transfer, args=(b, a, 200)).start()

デッドロックの問題に対する1つの解決策は、ロック中に各プログラムの一意のIDを割り当てることであり、唯一のロックを昇順で複数のルールを使用することができます。

第四に、スレッドプール

1、スレッドプールのプロフィール

スレッドプールは限りプログラムは、スレッドプールにタスク機能に提出されるように、スレッドプールは、それを実行するスレッドを開始して自由になり、システムの起動時にアイドル状態のスレッドの数が多いを作成することです。タスクの終了機能を実行すると、スレッドが死ぬが、次のタスク機能を待って、アイドル状態になったスレッド・プールに再び戻っていません。
システム内の並列スレッドのスレッドプールの番号を使用すると、効果的に制御することができます。システムは、同時多数のスレッドが含まれている場合は、システム性能の急激な減少につながる、とスレッドプールのパラメータ内のスレッドの最大数は、システムがこの数を超えない同時スレッドの数を制御する一方でさえ、Pythonインタプリタの崩壊につながります。
concurrent.futuresモジュールエグゼキュータは、エグゼキュータは、2つのサブカテゴリー、ThreadPoolExecutorは、スレッドプール、プールを作成するために使用ProcessPoolExecutorプロセスを作成するために使用される、すなわちThreadPoolExecutorとProcessPoolExecutorを提供する、抽象基底クラススレッドプールです。
Exectuorは、共通のインターフェースは、以下の提供:
submit(fn, *args, **kwargs):関数fnは、スレッドプールに提出されます。関数fnに渡される引数のパラメータに代わって、それはタプル型で、 FN関数パラメータに渡されたキーワード引数の形でkwargsからの代表は、辞書の種類です。提出方法は、Futureオブジェクトを返す
map(func, *iterables, timeout=None, chunksize=1):map関数は非同期に実行プロセスがすぐに反復可能オブジェクトにマッピングするために複数のスレッドを開始します。
シャットダウン(待機= TRUE):スレッドプールを閉じます。
今後は、以下の方法を提供し、
キャンセル():スレッド化タスクの将来の代理をキャンセルします。タスクが実行されている場合は、取り返しのつかない、それはFalseを返す、そうでない場合、プログラムがタスクをキャンセルし、Trueを返します。
()をキャンセル:今後は、タスクが正常にキャンセルされたかどうかのスレッドを表して返します。
()を実行している:未来が表している場合、スレッドがタスクを実行している、それはTrueを返し、キャンセルすることはできません。
行って():Funture代表スレッドのタスクが正常にキャンセルまたは実行完了している場合、Trueを返します。
結果(=なしタイムアウト):最後のリターン結果に代わって今後のスレッドタスクを取得します。将来スレッドタスクの代表が完了していない場合は、結果の方法は、タイムアウトパラメータが最も閉塞何秒を指定し、現在のスレッドをブロックします。
例外(タイムアウト=なし):スローされたスレッドに代わって今後の課題を取得していません。タスクが例外なく完了した場合、メソッドはNoneを返します。
add_done_callback(FN):将来はスレッドのタスクが正常に完了し、登録「コールバック関数」に代わってタスクをスレッド化され、プログラムが自動的にFN機能をトリガします。
スレッドプールを使用することがなくなった後は、スレッドプールを無効にしますスレッドプールのシャットダウン()メソッド、シャットダウンシーケンスが開始呼び出す必要があります。シャットダウンを呼び出した後()メソッドのスレッドプールは、もはや新しいタスクを受信されませんが、完全に提出されているすべてのタスクを実行します。すべてのタスクは、スレッドプール、死のスレッドプール内のすべてのスレッドを完了するために実行された場合。

2、スレッドプール

明示的max_worksを指定しない場合はThreadPoolExecutor(max_works)は、デフォルトのスレッド・プールは、作成CPU的数目*5スレッドの数を。

# -*- coding:utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
import threading
import time
import os
import string

class WorkThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        print('Process[%s]:%s start and run task' % (os.getpid(), threading.currentThread().getName()))
        time.sleep(2)
        return "Process[{}]:{} end".format(os.getpid(), threading.currentThread().getName())

def work_task(thread_name):
    print('Process[%s]:%s start and run task' % (os.getpid(), threading.currentThread().getName()))
    time.sleep(5)
    return "Process[{}]:{} end".format(os.getpid(), threading.currentThread().getName())

def get_call_back(future):
    print(future.result())

if __name__ == '__main__':
    print('main thread start')

    # create thread pool
    thread_pool = ThreadPoolExecutor(5)
    futures = []
    for i in range(5):
        thread = WorkThread()
        future = thread_pool.submit(thread.run)
        futures.append(future)

    for i in range(5):
        future = thread_pool.submit(work_task, i)
        futures.append(future)

    for future in futures:
        future.add_done_callback(get_call_back)

    # thread_pool.map(work_task, (2, 3, 4))
    thread_pool.shutdown()

# output:
# main thread start
# Process[718]:ThreadPoolExecutor-0_0 start and run task
# Process[718]:ThreadPoolExecutor-0_1 start and run task
# Process[718]:ThreadPoolExecutor-0_2 start and run task
# Process[718]:ThreadPoolExecutor-0_3 start and run task
# Process[718]:ThreadPoolExecutor-0_4 start and run task
# Process[718]:ThreadPoolExecutor-0_3 end
# Process[718]:ThreadPoolExecutor-0_3 start and run task
# Process[718]:ThreadPoolExecutor-0_1 end
# Process[718]:ThreadPoolExecutor-0_1 start and run task
# Process[718]:ThreadPoolExecutor-0_2 end
# Process[718]:ThreadPoolExecutor-0_2 start and run task
# Process[718]:ThreadPoolExecutor-0_0 end
# Process[718]:ThreadPoolExecutor-0_0 start and run task
# Process[718]:ThreadPoolExecutor-0_4 end
# Process[718]:ThreadPoolExecutor-0_4 start and run task
# Process[718]:ThreadPoolExecutor-0_2 end
# Process[718]:ThreadPoolExecutor-0_3 end
# Process[718]:ThreadPoolExecutor-0_1 end
# Process[718]:ThreadPoolExecutor-0_4 end
# Process[718]:ThreadPoolExecutor-0_0 end

3、プロセスプール

ProcessPoolExecutor(max_works)は、明示的に指定しないmax_works場合は、デフォルトのプロセスのプールが作成されますCPU的数目*5プロセスの数を。
プロセスプール同期方式:

from concurrent.futures import ProcessPoolExecutor
import os
import time
import random

def work_task(n):
    print('Process[%s] is running' % os.getpid())
    time.sleep(random.randint(1,3))
    return n**2

if __name__ == '__main__':
    start = time.time()
    pool = ProcessPoolExecutor()
    for i in range(5):
        obj = pool.submit(work_task, i).result()
    pool.shutdown()
    print('='*30)
    print("time: ", time.time() - start)

# output;
# Process[7372] is running
# Process[7373] is running
# Process[7374] is running
# Process[7375] is running
# Process[7372] is running
# ==============================
# time:  10.023026466369629

プロセス・プール非同期スキーム:

from concurrent.futures import ProcessPoolExecutor
import os
import time
import random

def work_task(n):
    print('Process[%s] is running' % os.getpid())
    time.sleep(random.randint(1, 3))
    return n**2

if __name__ == '__main__':
    start = time.time()
    pool = ProcessPoolExecutor()
    objs = []
    for i in range(5):
        obj = pool.submit(work_task, i)
        objs.append(obj)
    pool.shutdown()
    print('='*30)
    print([obj.result() for obj in objs])
    print("time: ", time.time() - start)

# output;
# Process[8268] is running
# Process[8269] is running
# Process[8270] is running
# Process[8271] is running
# Process[8270] is running
# ==============================
# [0, 1, 4, 9, 16]
# time:  2.0124566555023193

第五に、生産者 - 消費者モデル

import threading
from queue import Queue
from urllib.request import urlopen

ips = ["www.baidu.com",
       "www.taobao.com",
       "www.huawei.com",
       "www.alibaba.com",
       "www.meituan.com",
       "www.xiaomi.com"]
ports = [80, 443]

class Producer(threading.Thread):
    def __init__(self, _queue):
        super(Producer, self).__init__()
        self.queue = _queue

    def run(self):
        urls = ["http://%s:%s" % (ip, port) for ip in ips for port in ports]
        for url in urls:
            self.queue.put(url)

class Consumer(threading.Thread):
    def __init__(self, _queue):
        super(Consumer, self).__init__()
        self.queue = _queue

    def run(self):
        try:
            url = self.queue.get()
            urlopen(url)
        except Exception as e:
            print("%s is unknown url" % url)
        else:
            print("%s is ok" % url)

if __name__ == "__main__":
    # 实例化一个队列
    queue = Queue()

    for i in range(2):
        producer = Producer(queue)
        producer.start()

    for i in range(30):
        consumer = Consumer(queue)
        consumer.start()

# output:
# http://www.taobao.com:443 is unknown url
# http://www.huawei.com:443 is unknown url
# http://www.huawei.com:443 is unknown urlhttp://www.taobao.com:443 is unknown url
#
# http://www.baidu.com:80 is ok
# http://www.baidu.com:443 is unknown url
# http://www.xiaomi.com:443 is unknown url
# http://www.baidu.com:80 is ok
# http://www.baidu.com:443 is unknown url
# http://www.xiaomi.com:443 is unknown url
# http://www.alibaba.com:443 is unknown url
# http://www.alibaba.com:443 is unknown url
# http://www.meituan.com:443 is unknown urlhttp://www.meituan.com:443 is unknown url
#
# http://www.huawei.com:80 is ok
# http://www.huawei.com:80 is ok
# http://www.xiaomi.com:80 is ok
# http://www.xiaomi.com:80 is ok
# http://www.taobao.com:80 is ok
# http://www.meituan.com:80 is ok
# http://www.meituan.com:80 is ok
# http://www.taobao.com:80 is ok
# http://www.alibaba.com:80 is ok
# http://www.alibaba.com:80 is ok

おすすめ

転載: blog.51cto.com/9291927/2417778