我需要在脚本中等待,直到一定数量的条件成为现实?
我知道我可以使用条件变量和朋友来完成自己的事件,但我不想经历实现它的所有麻烦,因为一些对象属性更改来自包装C ++库中的外部线程(Boost。 Python),所以我不能只在一个类中劫持__setattr__
并在那里放置一个条件变量,这使我无法尝试从C ++创建和发出Python条件变量,或者包装一个本地变量并等待它在Python中,两者都听起来很繁琐,不必要地复杂和无聊。
是否有一种更简单的方法可以做到这一点,除非继续轮询病情?
理想情况下,这将是
res = wait_until(lambda: some_predicate, timeout)
if (not res):
print 'timed out'
答案 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