0

マシンにSSHで接続してアクションを実行するための簡単なpythonpexpectスクリプトを作成しました。次に、このアクションを複数のサーバーに対して実行する必要があります。リストを使用して、マルチスレッドを使用してすべてのサーバーを同時にヒットしています。私の問題は、すべてが同時に実行されているためです。各スレッドは同じサーバー名で実行されています。リストされたサーバーの1つだけを各スレッドで同時に実行する方法はありますか?

    #! /usr/bin/python
#Test script

import pexpect
import pxssh
import threading
import datetime



currentdate = datetime.datetime.now()
easterndate = (datetime.datetime.now() + datetime.timedelta(0, 3600))

#list of servers
serverlist = ["025", "089"]

#server number
sn = 0


ssh_new_conn = 'Are you sure you want to continue connecting'

class ThreadClass(threading.Thread):
  def run(self):

    index = 0
    sn = serverlist[index]
    print sn
    username = '[a username]'
    password = '[a password]'
    hostname = '%(sn)s.[the rest of the host url]' % locals()
    command = "/usr/bin/ssh %(username)s@%(hostname)s " % locals()
    index = index + 1
    now = datetime.datetime.now()

    print command
    p = pexpect.spawn(command, timeout=360)

    ***do some other stuff****

for i in range(len(severlist)):
  t = ThreadClass()
  t.start()

[更新]子スレッドなどを呼び出す親スレッドでこれを試してみるかもしれませんが、リストまたはある種のワークキューからマルチスレッドが機能するのはいいことですが。

4

1 に答える 1

1

この問題は、「すべてが同時に実行されている」こととは何の関係もありません。index = 0関数の開始時に明示的に設定しているrunので、もちろんすべてのスレッドはインデックス0で動作します。

各スレッドで1つのサーバーを処理する場合は、各スレッドオブジェクトにインデックスを渡すだけです。

class ThreadClass(threading.Thread):
    def __init__(self, index):
        super(ThreadClass, self).__init__()
        self.index = index
    def run(self):
        sn = serverlist[self.index]
        print sn
        # same code as before, minus the index = index + 1 bit

for i in range(len(severlist)):
    t = ThreadClass(i)
    t.start()

(もちろん、コードが機能しなくなる他のエラーのserverlist代わりに使用severlistして修正することをお勧めします。)

または、もっと簡単に言えば、snそれ自体を渡します。

class ThreadClass(threading.Thread):
    def __init__(self, sn):
        super(ThreadClass, self).__init__()
        self.sn = sn
    def run(self):
        print self.sn
        # same code as last version, but use self.sn instead of sn

for sn in severlist:
    t = ThreadClass(sn)
    t.start()

あるいは、本当にグローバル変数を使用したい場合は、それをグローバルにして、その周りにロックをかけます。

index = 0
index_lock = threading.Lock()

class ThreadClass(threading.Thread):
    def run(self):
        global index, index_lock
        with index_lock:
            sn = serverlist[index]
            index += 1
        print sn
        # same code as first version

ただし、明示的なワーカースレッドと作業対象のリストの代わりに、プールまたはエグゼキューターを使用する、はるかに単純な設計を検討することをお勧めします。例えば:

def job(sn):
    print sn
    # same code as first version again

with concurrent.futures.ThreadPoolExecutor() as executor:
    executor.map(job, serverlist)

これは、たとえば、4または8、あるいはその他の適切な「マジックナンバー」のジョブのみを同時に実行します。これは通常あなたが望むものです。max_workers=len(serverlist)ただし、サーバーごとに1つのスレッドが必要な場合は、ThreadPoolExecutorコンストラクターに渡すだけです。

読み取り、書き込み、間違え、デバッグなどのコードが大幅に削減されるだけでなく、より多くの機能も備えています。たとえば、サーバーからメインスレッドに結果や例外を戻すことができます。

于 2013-03-21T22:37:52.793 に答える