(day 30)GIL+スレッドに関する知識点

7221 ワード

目次
  • 昨日の内容
  • プロセス反発ロック
  • キュー
  • プロセス間通信
  • 生産者と消費者モデル
  • スレッド
  • スレッド
  • とは
  • スレッド
  • を使用する理由
  • スレッドを作成する2つの方法
  • スレッドオブジェクトのプロパティ
  • スレッド反発ロック
  • 今日の内容
  • GILグローバルインタプリタロック
  • マルチスレッドの役割
  • 計算密集型
  • IO密集型
  • デッドロック
  • 再帰ロック(RLock)
  • 信号量(semaphore)
  • スレッドキュー
  • FIFOキュー(Queue()
  • LIFOキュー(lifoQueue()
  • 優先キュー(PriorityQueue()


  • 昨日の内容


    プロセス反発ロック


    同時をシリアルにし、効率を犠牲にして、パケットを稼いでデータの安全を稼ぎました.
    mutex = Lock()
    #  
    mutex.acquire()
    #  
    mutex.release()

    キュー


    メモリにキュースペースを開くことに相当し、データの山を格納し、「先進的な先発」、パイプ(ブロック)+ロックに従うことができます.
    q = Queue()
    q.put() #  , , 
    q.put_nowait()  #  , 
    q.get() #  , , 
    q.get_nowait()  # , , 
    q.empty()  #  
    q.full()  #  

    プロセス間通信


    プロセス間のデータは共有されず、キューによる通信が可能

    生産者と消費者モデル


    生産者:生産データの
    消費者:データを使用する
    目的:このモデルをキューで実現し、需給のアンバランス問題を解決する

    スレッド


    スレッドとは


    プロセス:実行単位
    スレッド:実行単位
    注:プロセスを開くとスレッドがあり、プロセスが終了すると破棄されます.

    スレッドを使用する理由


    メモリリソースの節約
  • オープンスレッド
  • 新しいメモリ領域を開く
  • には、プライマリスレッド
  • が付属します.
  • オープンスレッド
  • 1プロセスは、複数のスレッド
  • を開くことができる.
  • オープンスレッドのリソースはプロセス
  • よりはるかに小さい.

    スレッドを作成する2つの方法

    #  1
    from threading import Thread
    def task():
        pass
    
    t = Thread(target = task)
    t.start()
    
    #  2
    class MyThread(Thread):
        def run():
            pass
        
    t= MyThread()
    t.start()

    スレッドオブジェクトのプロパティ

    current_thread().name  #  
    enumerate()  #  
    activeCount()  #  
    is_alive()  #  

    スレッド反発ロック

    from threading import Thread
    mutex = Lock()
    mutex.acquire()
    #  
    mutex.release(

    今日の内容


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


    Cpythonに基づいてGILを研究する
  • GILは本質的に反発ロック
  • である.
  • は、同じプロセスで複数のスレッドが同時に実行されることを阻止する.すなわち、単一プロセスでは複数のスレッドが並列に実行できず、
  • しか並列に実行できない.
  • GILの存在はスレッドの安全(ゴミ回収機構)
  • を保証するためである.
    注意:複数のスレッドが実行され、IO操作に遭遇するとすぐにGILグローバル解釈器ロックが解放されます.
    from threading import Thread
    import time
    
    number = 100
    
    def task():
        global number
        number2 = number
        time.sleep(1)
        nunmer = number2 -1
        
    for i in range(100):
        t = Thread(target = task)
        t.start()

    マルチスレッドの役割


    コンピューティング密集型


    シングルコアの場合、マルチスレッドが優先されます
    マルチコアの場合、マルチプロセスを優先的に使用
    まとめ:現在、ほとんどのコンピュータはマルチコアなので、コンピューティングが密集しているマルチプロセスを使用しています.
    from multiprocessing import Process
    from threading import  Thread
    import os,time
    
    def work():
        res = 0
        for i in range(100000000):
            res*=i
    
    if __name__ == '__main__':
        l = []
        print(os.cpu_count())
        start = time.time()
        for i in range(4):
            p = Process(target = work)
            # p = Thread(target = work)
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop = time.time()
        print(f'{stop-start}')

    IO密集型


    シングルコアの場合、マルチスレッドが優先されます
    マルチコアの場合、マルチスレッドが優先されます
    まとめ:IO密集型マルチスレッド使用
    from multiprocessing import Process
    from threading import  Thread
    import os,time
    
    def work():
        time.sleep(2)
        print('>>>>>>>>>')
    
    if __name__ == '__main__':
        l = []
        print(os.cpu_count())
        start = time.time()
        for i in range(40):
            # p = Process(target = work)
            p = Thread(target = work)
            l.append(p)
            p.start()
        for p in l:
            p.join()
        stop = time.time()
        print(f'{stop-start}')

    効率的に複数のIO密集型のプログラムを実行する:マルチプロセス+マルチスレッドを使用する

    デッドロック


    デッドロック現象:2つ以上のプロセスまたはスレッドが実行中にリソースを争うことによって互いに待つ現象であり、システムがデッドロック状態にあるか、デッドロックが発生したと呼ばれる.
    import time
    from threading import Lock,Thread
    
    mutex1 = Lock()
    mutex2 = Lock()
    
    def task():
        work1()
        work2()
    
    def work1():
        mutex1.acquire()
        print(' 1')
        mutex2.acquire()
        print(' 2')
        mutex2.release()
        print(' 1')
        mutex1.release()
        print(' 2')
    
    def work2():
        mutex2.acquire()
        time.sleep(1)
        mutex1.acquire()
        print(' 2')
        mutex1.release()
        print(' 1')
        mutex2.release()
        print(' 2')
    
    for i in range(10):
        t = Thread(target=task)
        t.start()

    再帰ロック(RLock)


    内部メンテナの1つのLockとcounter変数、counterはacquireの回数を記録して、releaseはcounterの回数を1減らして、counterが0の時だけ使用することができます
    デッドロックの問題を解決するために使用されます.チェーンロックに相当します.使わないか、一緒に持って行きます.
    import time
    from threading import RLock,Thread
    
    mutex1 = mutex2= RLock()
    
    def task():
        work1()
        work2()
    
    def work1():
        mutex1.acquire()
        print(' 1')
        mutex2.acquire()
        print(' 2')
        mutex2.release()
        print(' 1')
        mutex1.release()
        print(' 2')
    
    def work2():
        mutex2.acquire()
        time.sleep(1)
        mutex1.acquire()
        print(' 2')
        mutex1.release()
        print(' 1')
        mutex2.release()
        print(' 2')
    
    for i in range(10):
        t = Thread(target=task)
        t.start()

    しんごうりょう


    信号量:内蔵カウンタ、acquire内蔵カウンタ-1を呼び出すたびにrelease内蔵カウンタ+1を呼び出す.カウンタは0を下回ってはならない.カウンタが0の場合、acquireは他のスレッドがreleaseを呼び出すまでスレッドをブロックする
    ロックショップに相当
    import time
    from threading import Lock,Thread,Semaphore
    
    sm = Semaphore(10)
    
    def task():
        work1()
        work2()
    
    def work1():
        sm.acquire()
        print(' 1')
        sm.acquire()
        print(' 2')
        sm.release()
        print(' 1')
        sm.release()
        print(' 2')
    
    def work2():
        sm.acquire()
        time.sleep(1)
        sm.acquire()
        print(' 2')
        sm.release()
        print(' 1')
        sm.release()
        print(' 2')
    
    for i in range(10):
        t = Thread(target=task)
        t.start()

    スレッドキュー


    FIFOキュー(Queue()


    先入れ先出し
    import queue
    
    q=queue.Queue()
    q.put('first')
    q.put('second')
    q.put('third')
    
    print(q.get())
    print(q.get())
    print(q.get())
    '''
     ( ):
    first
    second
    third
    '''

    LIFOキュー(lifoQueue()


    後進後出
    import queue
    
    q=queue.LifoQueue()
    q.put('first')
    q.put('second')
    q.put('third')
    
    print(q.get())
    print(q.get())
    print(q.get())
    '''
     ( ):
    third
    second
    first
    '''

    優先順位キュー(PriorityQueue()

  • まず最初のパラメータからasciiテーブルの数値サイズ
  • を判断する.
  • 第2パラメータにおける漢字順
  • を判断する.
  • 再判断第2パラメータ中数字-->文字列数字--->中国語
  • はこのように
  • を押す.
    import queue
    
    q=queue.PriorityQueue()
    #put , ( , ), 
    q.put((20,'a'))
    q.put((10,'b'))
    q.put((30,'c'))
    
    print(q.get())
    print(q.get())
    print(q.get())
    '''
     ( , ):
    (10, 'b')
    (20, 'a')
    (30, 'c')
    '''