python同時プログラミングのマルチプロセス、マルチスレッド、非同期、およびコヒーレンスの詳細

6430 ワード

最近pythonの同時学習を行い,マルチプロセス,マルチスレッド,非同期,コヒーレンスをまとめた.一、マルチスレッド
マルチスレッドとは、1つのプロセスに複数の制御権を格納して、複数の関数を同時にアクティブにし、複数の関数の操作を同時に実行できるようにすることです.単一CPUのコンピュータであっても,異なるスレッドの命令間を絶えず切り替えることで,マルチスレッド同時実行の効果をもたらす.
マルチスレッドは同時システムに相当する.コンカレント・システムは、一般的に複数のタスクを同時に実行します.複数のタスクがリソースを共有でき、特に変数を同時に書き込む場合、マルチスレッド列車の切符販売システムなどの同期の問題を解決する必要があります.2つの命令、1つの命令は切符が売り切れたかどうかを検査し、もう1つの命令、複数のウィンドウは同時に切符を販売し、存在しない切符を売る可能性があります.
同時の場合,命令実行の前後順序はカーネルによって決定される.同じスレッドの内部では,命令は前後順に実行されるが,異なるスレッド間の命令はどちらが先に実行されるかをクリアすることは難しい.したがって、マルチスレッド同期の問題を考慮します.同期(synchronization)とは、一定の時間内に1つのスレッドのみがリソースにアクセスできることを意味します.
1、threadモジュール
2、threadingモジュールthreading.Threadはスレッドを作成します.
チケットの売れ残りと判断に反発ロックを加えることで、1つのスレッドがチケットの売れ残りがないと判断したばかりで、もう1つのスレッドがチケットの売れ行き操作を実行することはありません.
#! /usr/bin/python
#-* coding: utf-8 -*
# __author__ ="tyomcat"
import threading
import time
import os

def booth(tid):
  global i
  global lock
  while True:
    lock.acquire()
    if i!=0:
      i=i-1
      print "  :",tid,",    :",i
      time.sleep(1)
    else:
      print "Thread_id",tid,"No more tickets"
      os._exit(0)
    lock.release()
    time.sleep(1)

i = 100
lock=threading.Lock()

for k in range(10):

  new_thread = threading.Thread(target=booth,args=(k,))
  new_thread.start()


二、コンシステント
スレッドのプリエンプトスケジューリングとは異なり、コラボレーションスケジューリングです.コパスも単一スレッドですが、非同期+コールバック方式で書く非人間コードを同期のように書くことができます.
1.プロセスはpythonでジェネレータ(generator)によって実現することができる.
まずジェネレータとyieldについてしっかり理解しなければならない.
通常のpython関数を呼び出します.通常は、関数の最初の行のコードから実行され、return文、例外、または関数実行に終了します(Noneが暗黙的に返されたと考えられます).
関数が呼び出し元に制御権を返すと、すべてが終了することを意味します.シーケンスを生成できる関数を作成して「自分の仕事を保存」できる場合があります.これがジェネレータです(yieldキーワードを使用した関数).
「シーケンスを生成」できるのは、関数が通常の意味のように返されないためです.returnは、関数が実行コードの制御権を関数が呼び出された場所に返していることを意味する.「yield」の隠れた意味は、制御権の移行が一時的で自発的であり、私たちの関数は将来制御権を回収することを意味します.
生産者/消費者の例を見てみましょう.
#! /usr/bin/python
#-* coding: utf-8 -*
# __author__ ="tyomcat"
import time
import sys
#    
def produce(l):
  i=0
  while 1:
    if i < 10:
      l.append(i)
      yield i
      i=i+1
      time.sleep(1)
    else:
      return   
#    
def consume(l):
  p = produce(l)
  while 1:
    try:
      p.next()
      while len(l) > 0:
        print l.pop()
    except StopIteration:
      sys.exit(0)
if __name__ == "__main__":
  l = []
  consume(l)

プログラムがproduceのyield iに実行されると、generatorが返され、実行が一時停止し、customでp.next()を呼び出すと、プログラムはproduceのyield iに戻って実行を継続し、lに要素がappendされ、p.next()がStopIteration異常を引き起こすまでprint l.pop()を実行します.
2、Stackless Python
3、greenletモジュール
グリーンレットベースの実装では、Stackless Pythonに次ぐ性能であり、Stackless Pythonのほぼ倍遅く、他のスキームよりも1桁近く速い.実はgreenletは本当の同時メカニズムではなく、同じスレッド内で異なる関数の実行コードブロック間を切り替え、「あなたが実行している間、私が実行している間」を実施し、切り替えを行うときにいつ切り替え、どこに切り替えるかを指定しなければならない.
4、eventletモジュール
三、マルチプロセス1、サブプロセス(subprocessパッケージ)
pythonでは、subprocessパッケージを介してforkのサブプロセスを実行し、外部プログラムを実行します.
システムのコマンドを呼び出すときに、最初に考慮するosモジュール.OSでシステム()とos.popen()で操作します.しかし、この2つのコマンドは単純すぎて、実行中のコマンドに入力または読み出しコマンドの出力を提供したり、そのコマンドの実行状態を判断したり、複数のコマンドの並列を管理したりするなど、複雑な操作を完了できません.このときsubprocessのPopenコマンドは、必要な操作を効率的に完了します.
>>>import subprocess
>>>command_line=raw_input()
ping -c 10 www.baidu.com
>>>args=shlex.split(command_line)
>>>p=subprocess.Popen(args)

subprocessを利用する.PIPEは、複数のサブプロセスの入力と出力を接続し、パイプ(pipe)を構成する.
import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
print(out)

communicate()メソッドはstdoutおよびstderrからデータを読み出し、stdinに入力する.
2、マルチプロセス(multiprocessingパッケージ)
(1)、multiprocessingパケットはPythonにおけるマルチプロセス管理パケットである.threading.Threadは同様にmultiprocessingを利用することができる.プロセスオブジェクトを作成します.
プロセスプール(Process Pool)は、複数のプロセスを作成できます.
apply_async(func,args)はプロセスプールからプロセス実行funcを取り出し、argsはfuncのパラメータである.AsyncResultのオブジェクトが返され、get()メソッドを呼び出して結果を得ることができます.
close()プロセスプールは新しいプロセスを作成しません
join()waitプロセスプール内のすべてのプロセス.joinを呼び出すには、Poolに対してclose()メソッドを呼び出す必要があります.
#! /usr/bin/env python
# -*- coding:utf-8  -*-
# __author__ == "tyomcat"
# "     4 cpu"

from multiprocessing import Pool
import os, time

def long_time_task(name):
  print 'Run task %s (%s)...' % (name, os.getpid())
  start = time.time()
  time.sleep(3)
  end = time.time()
  print 'Task %s runs %0.2f seconds.' % (name, (end - start))

if __name__=='__main__':
  print 'Parent process %s.' % os.getpid()
  p = Pool()
  for i in range(4):
    p.apply_async(long_time_task, args=(i,))
  print 'Waiting for all subprocesses done...'
  p.close()
  p.join()
  print 'All subprocesses done.'


(2)、マルチプロセス共有リソース
メモリとManagerオブジェクトの共有:プロセスをサーバとして使用し、マネージャを確立してリソースを本当に保存します.
他のプロセスでは、パラメータを渡すか、アドレスに基づいてManagerにアクセスし、接続を確立した後、サーバ上のリソースを操作できます.
#! /usr/bin/env python
# -*- coding:utf-8  -*-
# __author__ == "tyomcat"

from multiprocessing import Queue,Pool
import multiprocessing,time,random

def write(q):

  for value in ['A','B','C','D']:
    print "Put %s to Queue!" % value
    q.put(value)
    time.sleep(random.random())


def read(q,lock):
  while True:
    lock.acquire()
    if not q.empty():
      value=q.get(True)
      print "Get %s from Queue" % value
      time.sleep(random.random())
    else:
      break
    lock.release()

if __name__ == "__main__":
  manager=multiprocessing.Manager()
  q=manager.Queue()
  p=Pool()
  lock=manager.Lock()
  pw=p.apply_async(write,args=(q,))
  pr=p.apply_async(read,args=(q,lock))
  p.close()
  p.join()
  print
  print "           "


四、非同期
スレッドもプロセスも、同期進数を使用しており、ブロックが発生すると、性能が大幅に低下し、CPUの潜在力を十分に利用できず、ハードウェア投資を浪費することができず、ソフトウェアモジュールの鉄板化、緊密な結合、切断できず、今後の拡張と変化に不利である.
プロセスでもスレッドでも、ブロック、切り替えのたびにシステムコール(system call)に陥る必要があります.まず、CPUにオペレーティングシステムのスケジューラを走らせ、その後、スケジューラによってどのプロセス(スレッド)を走るかを決定します.複数のスレッド間で反発するコードにアクセスするときにロックをかける必要があります.
現在流行している非同期serverは、nginxなどのイベント駆動に基づいている.
非同期イベント駆動モデルでは、ブロックを引き起こす操作を非同期操作に変換し、メインスレッドがこの非同期操作を開始し、この非同期操作の結果を処理します.すべてのブロックされた操作が非同期操作に変換されるため,理論的にはメインスレッドの大部分の時間は実際の計算タスクを処理し,マルチスレッドのスケジューリング時間が少なくなるため,このモデルの性能は通常比較的よい.
この記事は以下のとおりです.http://www.jb51.net/article/95971.htmここでお礼を言う