Pythonの並行プログラミング(9)スレッドキュー、イベントイベント、コルーチン

スレッドキュー、イベントイベント、コルーチン

  1. スレッドキュー

    • FIFO例:

      import queue #不需要通过threading模块里面导入,直接import queue就可以了,这是python自带的
      #用法基本和我们进程multiprocess中的queue是一样的
      q=queue.Queue()
      q.put('first')
      q.put('second')
      q.put('third')
      # q.put_nowait() #没有数据就报错,可以通过try来搞
      print(q.get())
      print(q.get())
      print(q.get())
      # q.get_nowait() #没有数据就报错,可以通过try来搞
      '''
      结果(先进先出):
      first
      second
      third
      '''
    • ラストアウト(LIFOスタック)例:

      import queue
      
      q=queue.LifoQueue() #队列,类似于栈,栈我们提过吗,是不是先进后出的顺序啊
      q.put('first')
      q.put('second')
      q.put('third')
      # q.put_nowait()
      
      print(q.get())
      print(q.get())
      print(q.get())
      # q.get_nowait()
      '''
      结果(后进先出):
      third
      second
      first
      '''
    • 例のプライオリティキュー

      import queue
      
      q=queue.PriorityQueue()
      #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
      q.put((-10,'a'))
      q.put((-5,'a'))  #负数也可以
      # q.put((20,'ws'))  #如果两个值的优先级一样,那么按照后面的值的acsii码顺序来排序,如果字符串第一个数元素相同,比较第二个元素的acsii码顺序
      # q.put((20,'wd'))
      # q.put((20,{'a':11})) #TypeError: unorderable types: dict() < dict() 不能是字典
      # q.put((20,('w',1)))  #优先级相同的两个数据,他们后面的值必须是相同的数据类型才能比较,可以是元祖,也是通过元素的ascii码顺序来排序
      
      q.put((20,'b'))
      q.put((20,'a'))
      q.put((0,'b'))
      q.put((30,'c'))
      
      print(q.get())
      print(q.get())
      print(q.get())
      print(q.get())
      print(q.get())
      print(q.get())
      '''
      结果(数字越小优先级越高,优先级高的优先出队):
      '''
    • 概要:これらの3例では、複数のスレッドが同じリソースやデータをつかむませんスレッドセーフキューです

  2. イベントイベント

    • 説明:オープン二つのスレッド、他のスレッドは、2つのスレッドを実行トリガー、ステージの中央に走る1つのスレッドの結合を増加させます

    • イベント方法:

      event.isSet():#返回event的状态值;
      
      event.wait():#如果 event.isSet()==False将阻塞线程;
      
      event.set(): #设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
      
      event.clear():#恢复event的状态值为False。
    • 入射せず、イベント、サーバ・スレッドへの接続を検出し、サーバへのねじ接続

      from threading import Thread
      from threading import current_thread
      import time
      flag=False#定义一个全局变量表示当前状态
      
      def check():
          print(f'{current_thread().name}检测服务器是否开启')
          time.sleep(3)#睡三秒
          global flag#使用global声明修改全局变量
          flag=True#讲flag改为true
          print('服务器已开启')
      
      def connect():
          while 1:
              print(f'{current_thread().name}等待连接')
              time.sleep(0.5)
              if flag:
                  print(f'{current_thread().name}连接成功')
                  break
      t1=Thread(target=check)
      t2=Thread(target=connect)
      t1.start()
      t2.start()
      # 结果:
      Thread-1监测服务器是否开启
      Thread-2等待连接
      Thread-2等待连接
      Thread-2等待连接
      Thread-2等待连接
      Thread-2等待连接
      Thread-2等待连接
      服务器已开启
      Thread-2 连接成功...
    • イベントイベントを使用します。

      from threading import Thread
      from threading import current_thread
      from threading import Event
      import time
      
      event=Event()#实例化Event事件 event默认为False
      def check():
          print(f'{current_thread().name}检测服务器连接')
          time.sleep(3)#休息三秒
          event.set()#将event改为True
          print(f'{current_thread().name}服务器已开启')
      
      def connect():
          print(f'{current_thread().name}等待连接')
          event.wait()#判断event是否为True
          print(f'{current_thread().name}连接成功')
      
      t1=Thread(target=check,)
      t2=Thread(target=connect,)
      t1.start()
      t2.start()
    • 別のスレッドが起動するかどうかを決定するために、スレッド・サーバの監視を開始するかどうかは、ディスプレイ接続が成功すると、唯一の成功したショーの失敗ではない、一回三回、1秒を接続

      from threading import Thread
      from threading import current_thread
      from threading import Event
      import time
      event=Event()
      def check():
          print(f'{current_thread().name}检查服务器连接')
          time.sleep(4)
          event.set()
          print(f'{current_thread().name}服务器已开启')
      
      
      def connect():
          count=1
          print(f'{current_thread().name}等待服务器连接')
          while count<=3:
              event.wait(1)
              if not event.is_set():
                  print(f'{current_thread().name}尝试连接{count}')
                  count+=1
              else:
                  print(f'{current_thread().name}连接成功')
                  break
          else:
              print(f'{current_thread().name}连接失败')
      
      t1=Thread(target=check)
      t2=Thread(target=connect)
      t1.start()
      t2.start()
  3. コルーチン

    • コルーチンとは何ですか?

      コルーチン:スレッド同時処理タスク

      シリアル:スレッドが実行した後、タスクを実行して、次のタスク

      パラレル:CPU、複数の複数のタスクを実行し、4つのタスクは、4つのCPUを実行します

      同時実行:同時に複数のタスクを実行するには、CPUがRUNのように見えます

      コンカレント社の本当のコアスイッチとホールド

      マルチスレッド:3スレッド処理タスク10、スレッド1ハンドル場合、このタスクは、別のスレッドに切り替えるために、オペレーティングシステムによって閉塞、CPUを満たし

      スレッド同時処理タスク:例えば、3つのタスクを実行するためのスレッド:

      協会のプロセス定義:コルーチン軽量スレッドはすなわちコルーチンは、自分自身をスケジュールするユーザプログラムによって制御され、ユーザー状態です。

      3つの方法で10回のミッションのシングルCPU同時実行:

      1、方法:オープンマルチプロセス同時実行、オペレーティングシステムの切替+ホールド。

      図2に示すように、二つの方法:複数の同時実行スレッドを介して、OS切替+ホールド。

      3、三方:オープン同時コルーチンの実行、タスク間の独自のCPUスイッチ+ 3ホールド付制御プログラム。

      これらの3つの実装、コルーチンが好ましく、これは、次のとおりです。

      オーバーヘッドを切り替える1.コルーチンが小さいほど、オペレーティングシステムのプログラム・レベル切替部は完全に感知でき、従ってより軽量であります

      2.コルーチン実行速度

      3.コルーチン長期占有CPUは、私はプログラム内のすべてのタスクを実行します。

      コルーチンの特徴:

      1. それは唯一のシングルスレッドで同時に実施されなければなりません
      2. ロックすることなく共有データを変更します
      3. ユーザプログラムコンテキスト複数の制御フローのそのスタックを保存(保持状態)
      4. 追加:他のコルーチンIO操作が自動的に切り替わりコルーチン経験
    • Greenlet

      • Greenletのpythonは本当のコルーチンモジュールは、ハンドオーバgreenletを完了するために使用され、あるサードパーティのモジュールであります

      • 同時2つのコア:スイッチング状態を保持した後、我々はゆっくり使用例からモジュール内に導入

        # 版本一:单切换
        def func1():
            print('in func1')
        
        def func2():
            print('in func2')
            func1()
            print('end')
        
        func2()
        
        # 版本二:切换+保持状态
        import time
        def gen():
            while 1:
                yield 1
                time.sleep(0.5)  # 手动设置IO,遇到IO无法自动切换
        
        def func():
            obj = gen()
            for i in range(10):
                next(obj)
        func()
        
        # 版本三:切换+保持状态,遇到IO自动切换
        from greenlet import greenlet
        import time
        def eat(name):
            print('%s eat 1' %name)  # 2
            g2.switch('taibai')  # 3
            time.sleep(3)
            print('%s eat 2' %name)  # 6
            g2.switch()  # 7
        
        def play(name):
            print('%s play 1' %name)  # 4
            g1.switch()  # 5
            print('%s play 2' %name)  # 8
        
        g1=greenlet(eat)
        g2=greenlet(play)
        
        g1.switch('taibai')  # 1 切换到eat任务
    • コルーチンモジュールgevent

      • geventをサードパーティライブラリが容易gevent同時同期または非同期プログラミングすることによって達成することができ、主モードはgeventで使用されるgreenlet、それはアクセスのPython C拡張モジュール軽量コルーチンの形態です。すべての主要なオペレーティング・システム・プロセス内で実行されますが、彼らは共同でスケジュールされているGreenlet。

      • いくつかのモジュールのGevent使用:

        # 用法:
        g1=gevent.spawn(func,1,2,3,x=4,y=5)#创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的,spawn是异步提交任务
        
        g2=gevent.spawn(func2)
        
        g1.join() # 等待g1结束
        
        g2.join() # 等待g2结束  有人测试的时候会发现,不写第二个join也能执行g2,是的,协程帮你切换执行了,但是你会发现,如果g2里面的任务执行的时间长,但是不写join的话,就不会执行完等到g2剩下的任务了
        
        # 或者上述两步合作一步:gevent.joinall([g1,g2])
      • 遭遇し、ブロッキングtime.sleepシミュレーションプログラムを使用します:

        import gevent
        import time
        from threading import current_thread
        def eat(name):
            print('%s eat 1' %name)
            print(current_thread().name)
            # gevent.sleep(2)
            time.sleep(2)
            print('%s eat 2' %name)
        
        def play(name):
            print('%s play 1' %name)
            print(current_thread().name)
            # gevent.sleep(1) # gevent.sleep(1)模拟的是gevent可以识别的io阻塞
            time.sleep(1)
            # time.sleep(1)或其他的阻塞,gevent是不能直接识别的需要用下面一行代码,打补丁,就可以识别了
            print('%s play 2' %name)
        
        
        g1 = gevent.spawn(eat,'egon')
        g2 = gevent.spawn(play,name='egon')
        print(f'主{current_thread().name}')
        g1.join()
        g2.join()
        # 结果: 
        主MainThread
        egon eat 1
        MainThread
        egon eat 2
        egon play 1
        MainThread
        egon play 2
      • 最終バージョン:

        import gevent
        from gevent import monkey
        monkey.patch_all()  # 打补丁: 将下面的所有的任务的阻塞都打上标记
        def eat(name):
            print('%s eat 1' %name)
            time.sleep(2)
            print('%s eat 2' %name)
        
        def play(name):
            print('%s play 1' %name)
            time.sleep(1)
            print('%s play 2' %name)
        
        
        g1 = gevent.spawn(eat,'egon')
        g2 = gevent.spawn(play,name='egon')
        
        # g1.join()
        # g2.join()#当多个协程需要等待我们可以使用下面一行代码
        gevent.joinall([g1,g2])
        # 结果:
        egon eat 1
        egon play 1
        egon play 2
        egon eat 2
      • ロードバランシング:それが動作する動作部を複数にわたって平衡拡散される負荷(タスク)を指し

      • nginxの: nginxの軽量Webサーバ/リバースプロキシサーバと少ないメモリ、高い並行性の所持することを特徴とする電子メール(IMAP / POP3)プロキシサーバ、です。

      • 要約:一般的に、我々は、最良の結果を達成するために、同時、並行性を達成するために+スレッド+コルーチン方法を作業中である場合、一般的に5つのプロセス、スレッド20の各(から4コアCPU、 5回CPUの数)は、各スレッドは500コルーチン、大規模なページをクロールするとき、我々は同時コルーチンを達成するために使用できるネットワークの遅延時間を待つを再生することができます。一般4CPU同時機械の最大数である同時= 5 * 20 * 500 = 50000同時の数、。nginxの最大荷重負荷分散が5ワットであるとき

        これらの20回の作業のためのシングルスレッドのコードでは、通常は両方の操作はブロック操作を持って計算し、私たちは、障害物の使用に、午前1時00分を遮断するタスク実行時の経験でタスク2を実行するために行くことができます。だから、Geventモジュールを使用して効率を改善するためです。

おすすめ

転載: www.cnblogs.com/zhangdadayou/p/11432113.html