Pexpect spawn.expect() 在检测进程输出方面似乎不可靠
我有一个类 ServerManager
,它使用 pexpect
监视另一个进程并与之交互。不幸的是,没有更干净的方法来做到这一点。该流程不提供 API。
ServerManager
需要监视进程的输出并在识别到特定模式时触发事件。因为有多个这样的模式需要监视,并且 pexpect
的 spawn.expect()
会阻塞当前线程,所以这些“侦听器”会被分离到与以下对象交互的单独线程中:当它们匹配其模式时的主线程。
一个这样的例子是等待用户连接/断开连接:
import pexpect
from threading import Thread,Lock
usersLock = Lock()
class ListenerThread(Thread):
def __init__(self, target, name=None, args=[], kwargs={}):
super(ListenerThread, self).__init__(name=name)
self.target = lambda: target(*args, **kwargs)
self.isStopped = False # add a way to safely halt this thread
def stop(self):
self.isStopped = True
def run(self):
while not self.isStopped: # run until told otherwise
try:
self.target()
except pexpect.TIMEOUT:
# we can't wait forever...
continue
except pexpect.EOF:
self.isStopped = True
class ServerManager(object):
def __init__(self):
self.process = pexpect.spawn(...) # Spawn the process
self.numberOfUsers = 0
# start up the listeners
self.listeners = []
connectListener = ListenerThread(self.waitForConnect, name="Connect listener")
connectListener.start()
disconnectListener = ListenerThread(self.waitForDisconnect, name="Disconnect listener")
disconnectListener.start()
self.listeners += [connectListener,disconnectListener] # keep track of the threads
def waitForConnect(self):
self.process.expect(...) # watch for the line that is printed when a user connects
usersLock.acquire()
try:
self.numberOfUsers += 1
finally:
usersLock.release()
def waitForDisconnect(self):
self.serverProcess.expect(...) # watch for the line that is printed when a user disconnects
usersLock.acquire()
try:
self.numberOfUsers -= 1
finally:
usersLock.release()
问题是“连接”和“断开”事件的触发非常不可靠。我创建了一个 ServerManager
实例,并连接/断开连接 10 次(每个操作之间等待大约 10 秒),在每次连接/断开连接后检查 numberOfUsers
。经过多次试验,最多只更新了大约 1/8 的时间。
这是 pexpect
中线程安全的问题吗?鉴于我与进程交互的唯一方法是监视其命令行输出,是否有更好的方法来监视此类事件?
I have a class, ServerManager
, which monitors and interfaces with another process using pexpect
. Unfortunately, there is not a cleaner way to do this. The process in question does not provide an API.
The ServerManager
needs to monitor the process's output and trigger events when it recognizes specific patterns. Because there are multiple such patterns to monitor, and pexpect
's spawn.expect()
blocks the current thread, these "listeners" get spun off into separate threads that interact with the main thread when they match on their pattern.
One such example is waiting for users to connect/disconnect:
import pexpect
from threading import Thread,Lock
usersLock = Lock()
class ListenerThread(Thread):
def __init__(self, target, name=None, args=[], kwargs={}):
super(ListenerThread, self).__init__(name=name)
self.target = lambda: target(*args, **kwargs)
self.isStopped = False # add a way to safely halt this thread
def stop(self):
self.isStopped = True
def run(self):
while not self.isStopped: # run until told otherwise
try:
self.target()
except pexpect.TIMEOUT:
# we can't wait forever...
continue
except pexpect.EOF:
self.isStopped = True
class ServerManager(object):
def __init__(self):
self.process = pexpect.spawn(...) # Spawn the process
self.numberOfUsers = 0
# start up the listeners
self.listeners = []
connectListener = ListenerThread(self.waitForConnect, name="Connect listener")
connectListener.start()
disconnectListener = ListenerThread(self.waitForDisconnect, name="Disconnect listener")
disconnectListener.start()
self.listeners += [connectListener,disconnectListener] # keep track of the threads
def waitForConnect(self):
self.process.expect(...) # watch for the line that is printed when a user connects
usersLock.acquire()
try:
self.numberOfUsers += 1
finally:
usersLock.release()
def waitForDisconnect(self):
self.serverProcess.expect(...) # watch for the line that is printed when a user disconnects
usersLock.acquire()
try:
self.numberOfUsers -= 1
finally:
usersLock.release()
The problem is that the "connect" and "disconnect" events are triggered very unreliably. I created an instance of the ServerManager
and connected/disconnected 10 times (waiting about 10 seconds between each action), checking numberOfUsers
after each connect/disconnect. It was only being updated about 1/8 of the time at best, over multiple trials.
Is this an issue with thread safety in pexpect
? Is there a better way to watch for these sorts of events given that my only means of interfacing with the process is by monitoring its command-line output?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这里有两个线程对同一个文件描述符进行阻塞调用。我将实现这是一个单线程异步事件循环。
expect
方法应该能够监视多个字符串,可以为一次调用的每个结果调用回调函数。我不确定 pexpect 实际上可以做到这一点(我不使用它),但请仔细查看它的文档。You have here two threads making a blocking call on the same file descriptor. I would implement this is a single threaded asynchronous event loop. The
expect
method should be able to watch for more than one string can invoke a callback function for each outcome from one call. I'm not sure pexpect can actually do this (I don't use it), but take a close look at it's documentation.