Python和shell中的多线程

Moh*_*ani 0 python multithreading

我有一个名为"nn.sh"的shell脚本,它在本地网络中获取一个ip地址并通过SSH连接到该ip,然后从该ip连续读取一些数据,并将结果附加到名为"log.txt"的文件中.服务器.

我需要编写一个Python代码在服务器上运行,该代码可能使用多线程在一个线程中运行此脚本,然后在另一个线程中读取文件"log.txt"中已有的值.我该怎么做呢?

我写了以下代码:

#!/usr/bin/python
import threading
import time
from subprocess import call, Popen, PIPE

exitFlag = 0

class loggerThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        print "Logging thread started ..."
    def run(self):
        with open("log.txt","at") as log: 
                call(['/bin/sh', 'nn.sh', '172.20.125.44', '10'], stdout = log)

class readerThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        print "Reading thread started ..."
    def run(self):
        while 1:
                with open("log.txt","r") as log:
                        lines = log.read().split("\n")
                        print "Reader thread  ..."
                        print lines[-1]


thread1 = loggerThread()
thread2 = readerThread()

thread1.start()
thread2.start()
Run Code Online (Sandbox Code Playgroud)

这里也是"nn.sh"的内容:

ssh -o IdentityFile=~/Dropbox/ALI/id_rsa -l root $1 <<EOF
    while :; 
        do date; 
           echo; 
           iwlist wlan0 scan 
           echo; 
           echo "#################################################################"; 
           sleep $2; 
        done;
EOF
Run Code Online (Sandbox Code Playgroud)

但是,如果我运行此代码,则"log.txt"中不会存储任何内容.有想法该怎么解决这个吗?

aba*_*ert 6

尝试通过像这样的文件将信息从一个进程(或线程)流式传输到另一个进程(或线程)是一个坏主意.您必须让编写器确保在每行之后刷新文件(并且不要在中间线刷新文件),您必须同步事物,以便只有在读取新数据而不是旋转时才读取文件尽可能快,您必须弄清楚如何检测何时有新数据要读取(这是特定于平台的)等.

这正是管道的用途.事实上,鉴于这一行:

from subprocess import call, Popen, PIPE
Run Code Online (Sandbox Code Playgroud)

...我怀疑你复制并粘贴了一些用管子做事的代码,因为否则,你为什么要导入PIPE

另外,我不确定你为什么认为你需要两个线程.如果必须将输入发送到shell脚本并读取输出,则使用两个线程可能会使这更容易.但是你要做的就是启动一个子进程,并在它可用时读取它的输出.所以只需从主线程中读取它的管道.

文档中有一些示例说明如何完全按照您的意愿执行操作.

from subprocess import call, Popen, PIPE
p = Popen(['/bin/sh', 'nn.sh', '172.20.125.44', '10'], stdout=PIPE)
for line in p.stdout:
    print line
p.wait()
Run Code Online (Sandbox Code Playgroud)

迭代管道将阻塞,直到另一条线可用,然后读取整条线,只要没有线路长度select.PIPE_BUF(保证至少为512).


如果由于某些其他原因需要将它放入一个线程中(例如,你需要在主线程中做一些其他的工作,而这个线程正在收集输出),那么你可以用与Python中任何其他线程完全相同的方式:要么创建threading.Thread子类,要么传递target函数.例如:

def nnsh():
    from subprocess import call, Popen, PIPE
    p = Popen(['/bin/sh', 'nn.sh', '172.20.125.44', '10'], stdout=PIPE)
    for line in p.stdout:
        print line
    p.wait()
t = threading.Thread(target=nnsh)
t.start()
# do a bunch of other stuff
t.join()
Run Code Online (Sandbox Code Playgroud)

(当然你可以把它变成一个守护程序线程,或者想出一个方法来发信号而不是加入无限超时等等; threading如果你知道你想要什么但是不要读基本教程或模块文档知道如何做到这一点,如果你被困在某个地方,就发布一个单独的新问题.)


如果你可能不得不在一些*nix平台上处理可笑的长行(尽管在至少最新版本的OS X,FreeBSD,Linux或Solaris上似乎没有必要),你可能需要手动循环代替:

buf = ''
while True:
    buf += p.stdout.read(select.PIPE_BUF)
    lines = buf.split('\n')
    for line in lines[:-1]:
        print line
    buf = lines[-1]
Run Code Online (Sandbox Code Playgroud)