Pexpect spawn.expect () кажется ненадежным при обнаружении вывода процесса - PullRequest
0 голосов
/ 21 августа 2011

У меня есть класс 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?Есть ли лучший способ следить за такого рода событиями, учитывая, что мой единственный способ взаимодействия с процессом - это мониторинг его вывода из командной строки?

1 Ответ

1 голос
/ 21 августа 2011

Здесь у вас есть два потока, выполняющих блокирующий вызов для одного и того же файлового дескриптора.Я бы реализовал это однопоточный асинхронный цикл обработки событий.Метод expect должен иметь возможность отслеживать более одной строки, может вызывать функцию обратного вызова для каждого результата одного вызова.Я не уверен, что pexpect действительно может это сделать (я им не пользуюсь), но внимательно изучите документацию.

...