Pexpect spawn.expect() 在检测进程输出方面似乎不可靠

发布于 2024-11-30 21:21:54 字数 2172 浏览 0 评论 0原文

我有一个类 ServerManager,它使用 pexpect 监视另一个进程并与之交互。不幸的是,没有更干净的方法来做到这一点。该流程不提供 API。

ServerManager 需要监视进程的输出并在识别到特定模式时触发事件。因为有多个这样的模式需要监视,并且 pexpectspawn.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

掐死时间 2024-12-07 21:21:54

这里有两个线程对同一个文件描述符进行阻塞调用。我将实现这是一个单线程异步事件循环。 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文