Pythonのネットワークプログラミング - グローバルインタプリタロック

GILロック

  1. GILロック

    • 定義:グローバルインタプリタロックがミューテックスで、データセキュリティの通訳を確保、効率性を犠牲にする、インタプリタのリソースを使用して一度に同時シリアル、一つのスレッドだけになります。

    • メモリ内のPYファイルの実行処理:

      • Pyのファイルを実行するとき、それはメモリ内のプロセスを開きます。
      • プロセスだけでなく、文書だけでなく、PythonインタプリタのPYを含み、コードのスレッドでPYファイルがインタプリタに引き渡されます、
      • インタプリタC言語コード・バイトにPythonコードを識別することができ、その後、バイナリコードに仮想マシンインタプリタバイトコードのCPUには、最終的に行います

      図は次のとおりです。

      最初のスレッドはGILロックスレッドを取得するときに1 2 3スレッドはCPUの実行時に実行スレッド1出会い閉塞または時間の期間GILのロックが解除されている間、スレッド1は、これを中断される、待つことができます閉塞または実行に直面したとき2または3のスレッドスレッドはGILロックは最後のスレッドがインタプリタを入力します。この時点でリリースされる一方で、CPUは、一時停止実行時間の期間の後、あまりにも、インタプリタにロックされます。

      上記から分かるように伴うロックGILの存在のために、複数のスレッドを含む単一のプロセスに直面したとき、CPythonのは、マルチコア並列処理を使用するが、単一のコア上で同時に実施することができるではありません。

      しかし、マルチスレッド、マルチプロセスは、複数のコアを利用することができます。

    • 役割:1インタプリタ内部のデータのセキュリティを確保するため、2ロック力、開発負担を軽減します。

    • 質問:マルチスレッドの単一プロセスは、マルチコアの利点を取ることができません

    • どのような状況マルチスレッドを使用すると、マルチプロセスの同時実行を確認する方法

      計算では、CPUより良い、しかし、I / O、それはより多くの無用のCPUであるため

        もちろん、プログラムを実行し、効率性の向上と、CPUは確かに(、そこには常に改善されますどのくらいの増加の大きさに関係なく)を向上させるプログラムは、実質的に純粋なまたは純粋なコンピューティングではないので、それはI / Oであります次のように、集中又はI / O集中反対側の端に番組を見るように計算されるべきです。

      #分析:
      我们有四个任务需要处理,处理方式肯定是要达到并发的效果,解决方案可以是:
      方案一:开启四个进程
      方案二:一个进程下,开启四个线程
      
      #单核情况下,分析结果: 
        如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
        如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜
      
      #多核情况下,分析结果:
        如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行,可以利用多核,方案一胜
        如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜
      
      
      #结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

      概要:マルチコアの前提の下で、IO集約型のタスク、マルチスレッドを使用する場合、タスクは、より複雑なプロセスを使用して、計算集約的である場合。

  2. 同時効率はCPythonの検証

    • 計算集約型のタスクが属します

      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()) #本机为8核
          start=time.time()
          for i in range(8):
              p=Process(target=work) #耗时7s多
              # p=Thread(target=work) #耗时15s多
              l.append(p)
              p.start()
          for p in l:
              p.join()
          stop=time.time()
          print('run time is %s' %(stop-start))

      タスクはマルチスレッドよりも効率的に計算集約、より複雑なプロセスであるときには見ることができます

    • IO集約型のタスクが属しています

      from multiprocessing import Process
      from threading import Thread
      import threading
      import os,time
      def work():
          time.sleep(2)
          print('===>')
      
      if __name__ == '__main__':
          l=[]
          print(os.cpu_count()) #本机为4核
          start=time.time()
          for i in range(40):
              # p=Process(target=work) #耗时5s多,大部分时间耗费在创建进程上
              p=Thread(target=work) #耗时2s多
              l.append(p)
              p.start()
          for p in l:
              p.join()
          stop=time.time()
          print('run time is %s' %(stop-start))

      タスクが集中的IOであるとき、それは、より複雑なプロセスより効率的なマルチスレッド、見ることができます。

  3. mutexロックとGIL関係

    1. GILロック保護は、データセキュリティのインタプリタであり、ミューテックス保護は、ファイル内のデータを保護することです。
    2. GILはロックを手動でロックし、ロックを解除する必要があります自動的にロックされたファイルのミューテックスをロックします。

    プログラムを実行すると、開い100スレッド、最初のスレッドが最初のGILロックを取得した後、ロックロックロックロック解除を取得する必要があり、最後のリリースGILロック:計算主体のすべてのスレッド。

    ラインは、すべてのIO集約型の言った:プログラムを実行すると、開い100スレッド、最初のスレッドが最初のGILロックを取得した後、ロックラッチを取得する必要がありますIOに直面したとき、CPUは、切り取っGILロック解除中、 GILロックに入るために第二のプロセスに起因ロックロックが解除されていない、保留中のブロックされ、共感、第三....

    概要:自分のミューテックスを追加するには、共有データを扱う場所で追加され、プラス拡大しない範囲にする必要があります。

  4. プロセスプールとスレッドプール

    プロセスプール:コンテナの配置プロセス。

    スレッドプール:コンテナのスレッドを置きます。

    場合によっては、マルチスレッドソケット通信の使用が終了しました。

    import socket
    from threading import Thread
    
    def communication(conn):
        while 1:
            try:
                from_client_data = conn.recv(1024)  # 阻塞
                print(from_client_data.decode('utf-8'))
                to_client_data = input('>>>').strip()
                conn.send(to_client_data.encode('utf-8'))
            except Exception:
                break
        conn.close()
    
    def customer_service():
    
        server = socket.socket()
        server.bind(('127.0.0.1', 8080))
        server.listen()
        while 1:
            conn,addr = server.accept()  # 阻塞
            print(f'{addr}客户:')
            t = Thread(target=communication,args=(conn,))
            t.start()
        server.close()
    
    if __name__ == '__main__':
        customer_service()

    マルチスレッドを使用することは、複数のクライアントとの通信を可能にするが、実際には無制限のオープンスレッドことができないので、満たすことができるコンピュータの場合には複数のスレッド(またはプロセス)を開くためにスレッド(またはプロセス)の数を制限するために行われるべきです。この時点では、スレッドプール(またはプロセス・プール)を使用する必要があります。次のように:

    import socket
    from concurrent.futures import ThreadPoolExecutor
    
    def communication(conn):
        while 1:
            try:
                from_client_data = conn.recv(1024)  # 阻塞
                print(from_client_data.decode('utf-8'))
                to_client_data = input('>>>').strip()
                conn.send(to_client_data.encode('utf-8'))
            except Exception:
                break
        conn.close()
    
    def customer_service(t):
    
        server = socket.socket()
        server.bind(('127.0.0.1', 8080))
        server.listen()
        while 1:
            conn,addr = server.accept()  # 阻塞
            print(f'{addr}客户:')
            t.submit(communication,conn)
        server.close()
    
    if __name__ == '__main__':
    
        t = ThreadPoolExecutor(2)
        customer_service(t)

    スレッドプールとセマフォの違いは何ですか?

    スレッドの数がスレッドプールは、スレッド多重化を介してメモリのオーバーヘッドを低減するために実際の作業を制御するために使用されます。スレッドプール内のスレッドの数はスレッド数がタスクを実行するために利用できる労働者があるまで待機するスレッドキューに移動する必要があるよりも、それは一定であると同時に作業することができます。

    使用Seamphoreは、あなたが実際にそこに実装されますどのように多くのスレッドが、どのように多くのスレッドを作成しますが、同時に実行できるスレッドの数が制限されます。しかし、あなただけのタスク実行スレッドプールとして提出するために作成されたスレッドプールのスレッドを使用すると、スレッドプールによって作成された実際の仕事、そして自分自身が管理し、スレッドプールの作業スレッドの実際の数をスレッド。

    https://blog.csdn.net/mryang125/article/details/81490783

おすすめ

転載: www.cnblogs.com/yaoqi17/p/11260062.html