Pythonマルチスレッドについても話します(例説明)

9058 ワード

最近の時間と結びつけて、pythonマルチスレッドの理解と使用に対して、pythonマルチスレッドの体得を実例の形式で示して、pythonのGIL(グローバル解釈ロック)はずっと非難されて、それはpythonのマルチスレッドがc+/javaのようにプロセッサのマルチコアを100%利用することができなくて、そのためpythonでマルチスレッドの同時を実現して、単一スレッド処理よりも効果が高いとは限りません.特に計算集約型タスク(CPU集約)では、この問題に関する回答を参照してください.[pythonマルチスレッドはプールの複数の放水口のようなものですが、同時に1つの放水口しか開けられません.開くと複数の放水口が同時に放水されますが、実際には異なるスレッド間で運転を切り替えています.実際の効果は、context switchの問題があるため、1つの放水口だけを開けて作業するほうがいいかもしれません.]したがって、CPU密集型タスクについては、同時完了を採用すれば、マルチプロセスを使用して実現することができ、IO密集型タスクについてはpythonマルチスレッドの同時効果は単一スレッドよりもずっと良い.context switchのコストはIO待機コストよりもずっと小さく、複数のスレッドはIOブロックの問題を防ぐことができるからだ.
1 pythonマルチスレッドの実装
python標準ライブラリには、_threadとthreadingの2つのモジュール実装マルチスレッドが用意されています.threadingは_threadをカプセル化し、より容易に実装できます.そのため、threadingモジュールの使用を推奨します.簡単な例を通じて、threadingモジュール実装マルチスレッドの一般的な使用方法を説明します.コードは以下の通りです.
#coding:utf-8

import threading
import time

class Thread(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self._num = num
        self.setDaemon(True)
    def run(self):
        global total,multex

        print threading.currentThread().getName()

        for x in xrange(0,int(self._num)):
            mutex.acquire()
            total += 1
            if total == 3000:
                print 'now:',total
                raw_input('>     ,      : ')

            mutex.release()
if __name__ == '__main__':
    global total,mutex
    total = 0
    mutex = threading.Lock()

    threads = []
    for x in xrange(0,40):
        threads.append(Thread(100))
    for t in threads:
        t.start()
        t.join()

    print total

このセグメントコードは40個のスレッドの作成を実現し、各スレッドはグローバル変数に対して固定値を増加し、最後にすべてのサブスレッドの実行が完了し、グローバル変数のカウント値を印刷し、スレッド実行間でinput()関数を通じて実行タスクの一時停止と返信を実現することができる.
以前にモジュールをインポートし、マルチスレッドコードの多重化を実現するために、一般的にクラスにカプセル化します.class Thread(threading.Thread):このクラスはthreadingモジュールのThreadクラスから継承され、次に、クラスを初期化し、親クラスの初期化関数threading.Thread.init(self)、およびいくつかのパラメータの初期化作業を呼び出します.self.setDaemon(True)ここではサブスレッドをデーモンスレッドとして設定し、.start()がスレッドを起動する前に実行しなければならないので、クラス初期化段階で完了すると、サブスレッドが終了しなくてもメインスレッドが完了するとサブスレッドがkillされ、デーモンスレッド防止プログラムが永久に停止するように設定する効果があります.(あるサブスレッドが何らかの理由で永続的に実行される場合):def run(self):ここではサブスレッド実行の関数を定義し、run関数を書き換えることで実現する必要があります.より一般的な方法は、初期化時に関数を1つ挿入し、runメソッドでこの関数を実行することです.次の例で説明します.mutex=threading.Lock()この文はスレッドロックを設定します.各スレッド間の通信を同時演算するには非常に注意が必要です.特にファイルの書き込み、グローバル変数の操作など、同時に1つのスレッドしか書き込み権限が得られません.これを実現するには、スレッドにロックをかけ、書き込み操作の前にmutex.acquire()がロックを取得し、操作の後にmutex.release()ロックを解除して、他のスレッドが操作を続けることを許可して、ロックメカニズムはスレッド間の正常な運転を保証する方法であるが、ロックメカニズムの下で実際にはシリアル書き込みファイルであるため、マルチスレッドの効率を損なう.次に、プログラムの中でThreadを実例化して、一般的に私はスレッドプールを作成して、サブスレッドを一括管理して、threads=[]スレッドプールを作成して、threads.append(Thread(100))Threadクラスを初期化してスレッドプールに追加し、最後に一括起動スレッド.start()および.join().join()の役割は、サブスレッドが完了する前に親スレッドがブロックされた状態ですべてのサブスレッドが再実行されるのを待つことです.
2 pythonマルチスレッドの実際の適用シーン
実际の需要はこのようです:今私は大量のエージェントipアドレスとポートを持っていて、あるウェブサイトに要求を送ってそのipアドレスが利用可能かどうかを判断する必要があります.ipの数が多くて、しかもIOの待ち时间が长いため、更に単一のスレッドはIOのブロックの问题が现れやすくて、総合的に、この需要を解决して単一のスレッドを采用するのはかなり気が狂っています..スレッドは同時に検証しますが、問題が来て、複数のスレッドがこれらのIPを同時に操作すると、スレッド間でどのように通信するかの問題に関連します.簡単で明確な方法は、キューQueueを使用することです.つまり、異なるサブスレッドにグローバルキューを渡すことで、ここではもちろんipアドレスです.サブスレッドはipを取り出すたびにキューからこのipを削除し、サブラインにスレッドがタスクを割り当てるときは繰り返されません.次に、キューが空でなければサブスレッドは実行を続け、キューが空であることを知って、サブスレッドが終了し、すべてのipが検証済みであることを示します.構想はこのようにして、この機能をdetect()クラスにカプセル化し、他のプログラムの呼び出しと修正を便利にし、具体的なコードは以下のように実現します.
#coding:utf-8

import socket
import urllib2
from spider.parser import Parser
import threading

#ip_queue = Parser.ip_queue
class Detector(object):
    def __init__(self,ip_queue):
        self.detect_url = 'http://ip.chinaz.com/getip.aspx'
        socket.setdefaulttimeout(2)
        self.ip_queue = ip_queue

    def detect(self):
        try:
            value = self.ip_queue.get_nowait()
            proxy_host ="http://ha:ha@"+value['ip']+':'+value['port']
            response = urllib2.urlopen(self.detect_url, proxies={"http": proxy_host})
            if response.getcode() == 200:
                #goodNum += 1
                print value['ip'],'good'
                return True
            else:
                #badNum += 1
                print value['ip'],'bad'
                return False
        except Exception,e:
            #print ip,'req error',response.getcode()
            #badNum += 1
            return False
    def run_detect(self,ip_queue):
        badNum = 0
        goodNum = 0
        mutex = threading.Lock()

        threads = []
        pool_num = 30
        for i in range(pool_num):
            t = Thread(self.detect,self.ip_queue)
            threads.append(t)
        for i in  range(pool_num):
            threads[i].start()
        for i in range(pool_num):
            threads[i].join()

class Thread(threading.Thread):
    def __init__(self,func,ip_queue):
        threading.Thread.__init__(self)
        self.func =  func
        self.ip_queue = ip_queue

    def run(self):
        while self.ip_queue.qsize() > 0:
            self.func() #self.ip_queue.get()['ip'],self.ip_queue.get()['port']

この体験がpythonマルチスレッドを勉強している学生に役立つことを望んでいます.文章に不適切な点があれば、伝言交流を歓迎します.