简体   繁体   English

无法使用python并行化(线程化)telnet连接

[英]cannot parallelize (threads) telnet connections with python

I have a code that will connect to several routers, using the telentlib, run some code within those, and finally write the output to a file. 我有一个代码,该代码将使用telentlib连接到多个路由器,在其中运行一些代码,最后将输出写入文件。 It runs smoothly. 运行平稳。

However, when I had to access lots of routers (+50) the task consumes a lot of time (the code runs serially, one router at a time). 但是,当我不得不访问许多路由器(+50)时,该任务会花费大量时间(代码是串行运行的,一次运行一个路由器)。 I thought then on implementing threads in order to accelerate the process. 我当时考虑实现线程以加快进程。

This is pretty much the code (just a snippet of it): 这几乎是代码(只是其中的一小段):

# We import the expect library for python
import telnetlib
import sys
import csv
import time
import threading

# --- Timers
TimeLogin = 10
TelnetWriteTimeout = 1
TelnetReadTimeout = 2
# --- CSV
FileCsv = "/home/lucas/Documents/script/file.csv"
# --- Extras
cr="\n"

# variables
IP = "A.B.C.D"
User = ["user","password"]
CliLogin = "telnet " + IP
Prompt = ["root@host.*]#"]
PromptLogin = ["login:"]
PromptLogout = ["logout"]
PromptPass = ["Password:"]
CliLine = "ls -l"

class MiThread(threading.Thread):  
    def __init__(self,num,datos):  
        threading.Thread.__init__(self)
        self.num = num
        self.datos = datos
        self.systemIP = self.datos[0]
        self.tn = telnetlib.Telnet(IP)
        self.tn.timeout = TimeLogin

        # File declaration
        self.FileOutGen = self.systemIP + "_commands"
        self.FileOutSend = self.systemIP + "_output"
        self.FileOutRx = self.systemIP + "_rx"      
        self.fg = open(self.FileOutGen,"w")
        self.fr = open(self.FileOutRx,"a")
        self.fs = open(self.FileOutSend,"w")

    def run(self):  
        print "Soy el hilo", self.num
        self.telnetLogin()
        self.runLs()
        self.telnetLogout()

    def telnetLogin(self):      
        i=self.tn.expect(PromptLogin)
        print i
        if i:
            writeTelnet(User[0],TelnetWriteTimeout)
            j=self.tn.expect(PromptPass)
            print j
            if j:
                writeTelnet(User[1],TelnetWriteTimeout)

    def telnetLogout(self):
        i=self.tn.expect(Prompt)
        if i:
            writeTelnet("exit",TelnetWriteTimeout)
            j=self.tn.expect(PromptLogout)
            if j:
                print "Logged out OK from SAM"

    def runLs(self):
        writeLog("Prueba de Ls " + self.systemIP)
        self.writeCsv(self.systemIP,1)
        i=self.tn.expect(Prompt,TimeLogin)
        print i
        if i:
            # Prompt
            CliLine = "ls -l "
            writeTelnet(CliLine,TelnetWriteTimeout)

    def writeCsv(self,inText,lastIn):
        lock.acquire(1)
        if lastIn==0:
            fc.write(inText + ",")
        elif lastIn==1:
            fc.write(inText + "\n")
        lock.release()

def writeTelnet(inText, timer):
    tn.write(inText + cr)
    time.sleep(timer)

def writeLog(inText):
    print (inText)
    t.fs.write("\n" + inText)

def printConsole(inText):
    print (inText)

oFile = csv.reader(open(FileCsv,"r"), delimiter=",", quotechar="|")

lock = threading.Lock()
routers = list(oFile)
threads_list = []

for i in range(len(routers)):
    FileOutCsv = "00_log.csv"

    # creating output file
    fc = open(FileOutCsv,"a")

    # running routine
    t = MiThread(i,routers[i])
    threads_list.append(t)
    t.start()

... everything runs nicely, but there is no gain in time since the t.join() will force a thread to complete before running the next one! ...一切运行良好,但是没有时间收益,因为t.join()将强制线程在运行下一个线程之前完成!

The fact of serializing the threads (meaning, using the t.join()) makes me think that some memory spaces are being shared because the problem arises when I do want to parallelize them (commenting out the t.join()). 序列化线程的事实(意味着使用t.join())使我认为正在共享一些内存空间,因为当我确实要对其进行并行化(注释掉t.join())时就会出现问题。

Is there anything wrong that I'm doing? 我做错什么了吗? I can provide more information if needed but I really do not know what is it that I'm doing wrong so far ... 如果需要,我可以提供更多信息,但我真的不知道到目前为止我做错了什么...

So after some digging, the error was found. 因此,在进行一些挖掘之后,发现了错误。

Before, the function writeTelnet() was declared outside the class. 之前,函数writeTelnet()是在类外部声明的。 Once moved inside of it and properly being referenced by the rest (ie: self.writeTelnet()) everything worked so far as expected. 一旦移入其中并被其余部分正确引用(即:self.writeTelnet()),一切就可以按预期进行。

Here's the snippet of the new code: 这是新代码的片段:

class MiThread(threading.Thread):  
    def __init__(self,num,datos):  
        threading.Thread.__init__(self)
        self.num = num
        self.datos = datos
        self.systemIP = self.datos[0]
        self.tn = telnetlib.Telnet(IP)
        self.tn.timeout = TimeLogin

        # File declaration
        self.FileOutGen = self.systemIP + "_commands"
        self.FileOutSend = self.systemIP + "_output"
        self.FileOutRx = self.systemIP + "_rx"      
        self.fg = open(self.FileOutGen,"w")
        self.fr = open(self.FileOutRx,"a")
        self.fs = open(self.FileOutSend,"w")

    [ . . . ]

    def writeTelnet(self,inText, timer):
        self.tn.write(inText + ch_cr)
        time.sleep(timer)

oFile = csv.reader(open(FileCsv,"r"), delimiter=",", quotechar="|")
routers = list(oFile)

for i in range(len(routers)):   
    # creating output file
    fc = open(FileOutCsv,"a")

    # running routine
    t = MiThread(i,routers[i])
    t.start()

And it's now clear (at least to me): Since the different threads need at some point to write into their telnet's connection, they need unambiguously to identify it. 现在很清楚了(至少对我来说是这样):由于不同的线程在某个时候需要写入其telnet的连接,因此他们需要明确地进行标识。 The only way that I've found to do it is to include the function inside the class. 我发现这样做的唯一方法是将函数包含在类中。

Thank you all, 谢谢你们,

Lucas 卢卡斯

From past experience, you need to start all of the threads and have them join after they have all started. 根据过去的经验,您需要启动所有线程,并在所有线程启动后将它们加入。

thread_list = []
for i in range(routers):
    t = MiThread(i, routers[i])
    threadlist.append(t)
    t.start()

for i in thread_list:
    i.join()

This will start every thread and then wait for all threads to complete before moving on. 这将启动每个线程,然后等待所有线程完成后再继续。

I think you can bunch them up. 我想你可以把它们捆起来。 something like below. 像下面这样。 (not tried) (未尝试)

count=20
start=1
for i in range(len(routers)):
  if start == count :
    for _myth in range(1,i+1):
        thread_list[_myth].join()
    start+=1
FileOutCsv = "00_log.csv"

# creating output file
fc = open(FileOutCsv,"a")

# running routine
t = MiThread(i,routers[i])
threads_list.append(t)
t.start()
start+=1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM