0

我编写了一个简单的 python pexpect 脚本来 ssh 进入机器并执行操作。现在我需要对多台服务器执行此操作。我正在使用一个列表来同时使用多线程访问所有服务器。我的问题是由于所有内容都同时运行,每个线程都在相同的服务器名称上运行。有没有办法同时让每个线程只运行列出的服务器之一?

    #! /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 上工作。

如果您希望每个线程处理一个服务器,只需将索引传递给每个线程对象:

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)ThreadPoolExecutor构造函数即可。

除了读取、写入、出错、调试等方面的代码要少得多之外,它还具有更多功能——例如,您可以将结果和/或异常从服务器返回到主线程。

于 2013-03-21T22:37:52.793 回答