在Python中有一种简单的方法可以等到某些条件成立吗?

时间:2010-05-07 02:33:15

标签: python

我需要在脚本中等待,直到一定数量的条件成为现实?

我知道我可以使用条件变量和朋友来完成自己的事件,但我不想经历实现它的所有麻烦,因为一些对象属性更改来自包装C ++库中的外部线程(Boost。 Python),所以我不能只在一个类中劫持__setattr__并在那里放置一个条件变量,这使我无法尝试从C ++创建和发出Python条件变量,或者包装一个本地变量并等待它在Python中,两者都听起来很繁琐,不必要地复杂和无聊。

是否有一种更简单的方法可以做到这一点,除非继续轮询病情?

理想情况下,这将是

res = wait_until(lambda: some_predicate, timeout)
if (not res):
    print 'timed out'

10 个答案:

答案 0 :(得分:23)

不幸的是,满足您的限制的唯一可能性是定期民意调查,例如......:

import time

def wait_until(somepredicate, timeout, period=0.25, *args, **kwargs):
  mustend = time.time() + timeout
  while time.time() < mustend:
    if somepredicate(*args, **kwargs): return True
    time.sleep(period)
  return False

等。如果somepredicate可以被分解(例如,如果已知它是几个子句的and,则可以通过多种方式对其进行优化,特别是如果某些子句通过可通过{检测到 - 进而进行优化。 {1}} s或者其他等等,但是按照你要求的一般术语,这种效率低下的方法是唯一的出路。

答案 1 :(得分:3)

你基本上回答了自己的问题:没有。

由于您正在处理boost.python中的外部库,这可能会在闲暇时更改对象,因此您需要让这些例程调用事件处理程序刷新,或者使用条件。

答案 2 :(得分:2)

以下是Alex解决方案的线程扩展:

import time
import threading

# based on https://stackoverflow.com/a/2785908/1056345                                                                                                                                                                                                                                                                         
def wait_until(somepredicate, timeout, period=0.25, *args, **kwargs):
    must_end = time.time() + timeout
    while time.time() < must_end:
        if somepredicate(*args, **kwargs):
            return True
        time.sleep(period)
    return False

def wait_until_par(*args, **kwargs):
    t = threading.Thread(target=wait_until, args=args, kwargs=kwargs)
    t.start()
    print ('wait_until_par exits, thread runs in background')

def test():
    print('test')

wait_until_par(test, 5)

答案 3 :(得分:2)

这是另一种解决方案。目的是使线程以非常精确的顺序互相等待,然后再执行一些工作。这项工作可能会花费未知的时间。持续轮询不好是因为两个原因:它占用了CPU时间,并且在满足条件后无法立即开始执行操作。

class Waiter():

    def __init__(self, init_value):
        self.var = init_value
        self.var_mutex = threading.Lock()
        self.var_event = threading.Event()

    def WaitUntil(self, v):
        while True:
            self.var_mutex.acquire()
            if self.var == v:
                self.var_mutex.release()
                return # Done waiting
            self.var_mutex.release()
            self.var_event.wait(1) # Wait 1 sec

    def Set(self, v):
        self.var_mutex.acquire()
        self.var = v
        self.var_mutex.release()
        self.var_event.set() # In case someone is waiting
        self.var_event.clear()

测试方式

class TestWaiter():

    def __init__(self):
        self.waiter = Waiter(0)
        threading.Thread(name='Thread0', target=self.Thread0).start()
        threading.Thread(name='Thread1', target=self.Thread1).start()
        threading.Thread(name='Thread2', target=self.Thread2).start()

    def Thread0(self):
        while True:
            self.waiter.WaitUntil(0)
            # Do some work
            time.sleep(np.random.rand()*2)
            self.waiter.Set(1)

    def Thread1(self):
        while True:
            self.waiter.WaitUntil(1)
            # Do some work
            time.sleep(np.random.rand())
            self.waiter.Set(2)

    def Thread2(self):
        while True:
            self.waiter.WaitUntil(2)
            # Do some work
            time.sleep(np.random.rand()/10)
            self.waiter.Set(0)

等待多处理程序:

import multiprocessing as mp
import ctypes

class WaiterMP():
    def __init__(self, init_value, stop_value=-1):
        self.var = mp.Value(ctypes.c_int, init_value)
        self.stop_value = stop_value
        self.event = mp.Event()

    def Terminate(self):
        self.Set(self.stop_value)

    def Restart(self):
        self.var.value = self.init_value

    def WaitUntil(self, v):
        while True:
            if self.var.value == v or self.var.value == self.stop_value:
                return
            # Wait 1 sec and check aiagn (in case event was missed)
            self.event.wait(1)

    def Set(self, v):
        exit = self.var.value == self.stop_value
        if not exit: # Do not set var if threads are exiting
            self.var.value = v
        self.event.set() # In case someone is waiting
        self.event.clear()

如果这仍然不是最佳解决方案,请发表评论。

答案 4 :(得分:0)

这对我有用

direction = ''
    t = 0
    while direction == '' and t <= 1:
        sleep(0.1)
        t += 0.1

这是在等待信号的同时确保时间限制为1秒

答案 5 :(得分:0)

建议的解决方案:

def wait_until(delegate, timeout: int):
end = time.time() + timeout
while time.time() < end:
    if delegate():
        return True
    else:
        time.sleep(0.1)
return False

用法:

wait_until(lambda: True, 2)

答案 6 :(得分:0)

另一个不错的软件包是waiting-https://pypi.org/project/waiting/

安装:

pip install waiting

用法: 您传递了一个每次都会作为条件,超时被调用的函数,(这很有用)您可以传递等待的描述,如果您收到TimeoutError,则会显示该描述。

使用功能:

from waiting import wait


def is_something_ready(something):
    if something.ready():
        return True
    return False


# wait for something to be ready
something = # whatever

wait(lambda: is_something_ready(something), timeout=120, waiting_for="something to be ready")

# this code will only execute after "something" is ready
print("Done")

注意:该函数必须返回一个布尔值-等待结束时为True,否则为False

答案 7 :(得分:0)

从计算的角度来看,必须在某个时间检查所有条件。如果您有两部分代码,一部分生成条件更改,另一部分在某些条件为真时应执行,您可以执行以下操作:

将更改条件的代码(例如,主线程)和应在某些条件为真时启动的代码放在工作线程中。

from threading import Thread,Event

locker = Event()

def WhenSomeTrue(locker):
    locker.clear() # To prevent looping, see manual, link below
    locker.wait(2.0) # Suspend the thread until woken up, or 2s timeout is reached
    if not locker.is_set(): # when is_set() false, means timeout was reached
        print('TIMEOUT')
    else:
    #
    # Code when some conditions are true
    #
worker_thread = Thread(target=WhenSomeTrue, args=(locker,))
worker_thread.start()

cond1 = False
cond2 = False
cond3 = False

def evaluate():
    true_conditions = 0

    for i in range(1,4):
        if globals()["cond"+str(i)]: #access a global condition variable one by one
            true_conditions += 1     #increment at each true value
    if true_conditions > 1:
        locker.set() # Resume the worker thread executing the else branch
    #Or just if true_conditions > 1: locker.set();
    #true_conditions would need be incremented when 'True' is written to any of those variables

#
# some condition change code
#
evaluate()

有关此方法的更多信息,请访问:https://docs.python.org/3/library/threading.html#event-objects

答案 8 :(得分:-1)

这是我在一个项目中使用的代码:

import time
def no() :
    if (Condition !!!) :
        it got true
        oh()
    else:
        time.sleep(1) /Don't remove or don't blame me if ur system gets ""DEAD""
        no()
def oh() :   /Ur main program 
    while True:
        if(bla) :
            .......
            no()
        else :
            time.sleep(1)
            oh()

oh()

希望有帮助

答案 9 :(得分:-1)

方法如下:

import time

i = false

while i == false:
    if (condition):
        i = true
        break