python: эквивалент SIGALRM для Windows

У меня есть такой декоратор:

def timed_out(timeout):
    def decorate(f):
        if not hasattr(signal, "SIGALRM"):
            return f

        def handler(signum, frame):
            raise TimedOutExc()

        @functools.wraps(f)
        def new_f(*args, **kwargs):
            old = signal.signal(signal.SIGALRM, handler)
            signal.alarm(timeout)
            try:
                result = f(*args, **kwargs)
            finally:
                signal.signal(signal.SIGALRM, old)
            signal.alarm(0)
            return result

        new_f.func_name = f.func_name
        return new_f

    return decorate

Код делает что-либо только в Linux, хотя, как и в Windows, SIGALRM нет. Каким будет самый простой способ заставить этот код работать и в Windows?


person Claudiu    schedule 07.12.2011    source источник


Ответы (2)


Это не очень красиво, но мне пришлось сделать что-то подобное кроссплатформенным способом, и я придумал использовать отдельный поток. Системы на основе сигналов не работали надежно на всех платформах.

Использование этого класса может быть заключено в декоратор или преобразовано в with обработчик контекста.

YMMV.

#!/usr/bin/env python2.7
import time, threading

class Ticker(threading.Thread):
  """A very simple thread that merely blocks for :attr:`interval` and sets a
  :class:`threading.Event` when the :attr:`interval` has elapsed. It then waits
  for the caller to unset this event before looping again.

  Example use::

    t = Ticker(1.0) # make a ticker
    t.start() # start the ticker in a new thread
    try:
      while t.evt.wait(): # hang out til the time has elapsed
        t.evt.clear() # tell the ticker to loop again
        print time.time(), "FIRING!"
    except:
      t.stop() # tell the thread to stop
      t.join() # wait til the thread actually dies

  """
  # SIGALRM based timing proved to be unreliable on various python installs,
  # so we use a simple thread that blocks on sleep and sets a threading.Event
  # when the timer expires, it does this forever.
  def __init__(self, interval):
    super(Ticker, self).__init__()
    self.interval = interval
    self.evt = threading.Event()
    self.evt.clear()
    self.should_run = threading.Event()
    self.should_run.set()

  def stop(self):
    """Stop the this thread. You probably want to call :meth:`join` immediately
    afterwards
    """
    self.should_run.clear()

  def consume(self):
    was_set = self.evt.is_set()
    if was_set:
      self.evt.clear()
    return was_set

  def run(self):
    """The internal main method of this thread. Block for :attr:`interval`
    seconds before setting :attr:`Ticker.evt`

    .. warning::
      Do not call this directly!  Instead call :meth:`start`.
    """
    while self.should_run.is_set():
      time.sleep(self.interval)
      self.evt.set()
person Trey Stout    schedule 07.12.2011
comment
Кажется, я не могу заставить приведенный выше код работать так, как я использую этот тайм-аут codepen.io/illsio/pen/ oNbybRg Я пробовал использовать t.evt.wait, где t = Tiker (3.0) t.start (), но это не помогает. - person ill; 10.07.2020

Этот ответ работает только в Cygwin

Я также считаю, что этот код декоратора тайм-аута очень удобен. (Первоначально я нашел это в ответе на этот вопрос: Как ограничить время выполнения вызова функции?)

Чтобы он работал в Windows, я использую Python, установленный с Cygwin.

Я запускаю setup-x86_64.exe, затем выбираю пакет python3 из папки Python. (Или, если вы предпочитаете Python 2, пакет python.)

Чтобы переименовать python3 в python2, я определяю псевдоним

alias python=python3

из командной строки Cygwin. Поскольку я не очень часто использую эту функцию, я, вероятно, не буду помещать ее в .bashrc или что-то еще.

Связанный вопрос: Сигнал Python не работает даже на Cygwin?

person Josiah Yoder    schedule 17.11.2016
comment
Может ли кто-нибудь указать, что не так с этим ответом? Сам не вижу с этим проблем. (Я автор) - person Josiah Yoder; 10.07.2017
comment
На самом деле ты не помог. Ваше предложение - отклонение, а не решение. - person Geoff; 15.03.2018
comment
Спрашивается, какой самый простой способ заставить этот код работать и в Windows? Я отвечаю. Чтобы он работал в Windows, я использую Python, установленный с Cygwin. Это решение, которое помогло мне. - person Josiah Yoder; 16.03.2018
comment
Он работает в Cygwin - это лишь небольшое улучшение, скажем, на виртуальной машине Linux, работающей на хосте Windows. Это не ответ, это просто обходной путь. - person Wedge; 15.05.2019