我编写了一个简单的 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() 

[更新] 我可能只是尝试使用调用子线程的父线程来执行此操作等等......尽管如果多线程可以从列表或某种工作队列中工作那就太好了。

请您参考如下方法:

该问题与“所有内容同时运行”无关。您在 run 函数的开头显式设置 index = 0,因此当然每个线程都在索引 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 个或其他一些好的“魔数(Magic Number)”作业。这通常就是你想要的。但是,如果您希望每个服务器只有一个线程,只需将 max_workers=len(serverlist) 传递给 ThreadPoolExecutor 构造函数即可。

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


评论关闭
IT源码网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!