python 条件变量 `wait_for` 谓词未立即返回
python condition variable `wait_for`predicate not immediately returned
我正在尝试实现同步端点,其中将作业排队,等待作业完成,然后 return 结果。
lock = Condition()
def predicate(job_in_queue):
job_in_queue.refresh()
print(job_in_queue.get_status())
print(datetime.datetime.now())
if job_in_queue.get_status() == "finished":
return True
return False
print(datetime.datetime.now())
with lock:
if lock.wait_for(lambda: predicate(job), timeout=10):
print("indeed notified")
else:
print("failed to notify")
print(datetime.datetime.now())
print(datetime.datetime.now())
return job.result
python条件变量的wait_for
方法:wait_for(predicate, timeout=None)
,会停在这一行,等待callable传入,predicate
,returns True
,然后继续执行后面的代码。参考 the documentation.
但是,根据我的打印行,predicate
似乎没有经常被检查。当第一次调用 wait_for
时,它只在第一次通过 in/the 时检查一次,然后它处于空闲状态,仅在 t=timeout
秒后第二次检查,其中 timeout
是我传入的数字。在我的打印行中,它仅在 10 秒后检查 predicate
(我在上面的代码中指定的 timeout
值)。
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:23.954320
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT queued
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:23.974196
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT finished
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:33.986337
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT indeed notified
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:33.987215
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:33.987233
我进一步验证了问题确实是 predicate
没有通过将 timeout
更改为 15 来不断检查,它再次只检查 15 之后的 predicate
结果秒。
有没有办法让 predicate
经常检查这里?不是 while True
忙等待,因为它会占用 CPU(并且永远不会通过代码审查)。或者 threading.Condition.wait_for
是去这里的正确方法吗?
Condition 对象的目的是同步两个或多个线程的activity。当 Thread-1 调用 Condition.wait
时,它就被阻塞了。因此,它不可能像您希望的那样检查谓词何时变为真。相反,它必须等待 Thread-2 做一些可能导致谓词变为真的事情。在那一刻,Thread-2 应该通知 Condition 对象。对 notify
的调用导致 Thread-1 唤醒并检查谓词。如果谓词现在为真,Thread-1 继续执行;否则它会再次阻塞。
文档中是这样说的:
》忽略超时特性,调用该方法大致等同于这样写:
while not predicate():
cv.wait()
"
如果包含超时值,Thread-1 会在超时间隔后唤醒,而不管另一个线程是否调用了 notify。正如您观察到的那样,这会导致对谓词进行检查。
如果您想以合理的频率检查谓词,请提供足够短的超时时间或
确保另一个线程在适当的时间发出通知调用。
但是如果您不使用它来同步两个或多个线程,Condition 是错误的工具。如果你需要一个紧密的循环,写一个紧密的循环。
我正在尝试实现同步端点,其中将作业排队,等待作业完成,然后 return 结果。
lock = Condition()
def predicate(job_in_queue):
job_in_queue.refresh()
print(job_in_queue.get_status())
print(datetime.datetime.now())
if job_in_queue.get_status() == "finished":
return True
return False
print(datetime.datetime.now())
with lock:
if lock.wait_for(lambda: predicate(job), timeout=10):
print("indeed notified")
else:
print("failed to notify")
print(datetime.datetime.now())
print(datetime.datetime.now())
return job.result
python条件变量的wait_for
方法:wait_for(predicate, timeout=None)
,会停在这一行,等待callable传入,predicate
,returns True
,然后继续执行后面的代码。参考 the documentation.
但是,根据我的打印行,predicate
似乎没有经常被检查。当第一次调用 wait_for
时,它只在第一次通过 in/the 时检查一次,然后它处于空闲状态,仅在 t=timeout
秒后第二次检查,其中 timeout
是我传入的数字。在我的打印行中,它仅在 10 秒后检查 predicate
(我在上面的代码中指定的 timeout
值)。
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:23.954320
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT queued
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:23.974196
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT finished
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:33.986337
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT indeed notified
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:33.987215
2021-07-15T13:48:33.98+0800 [APP/PROC/WEB/0] OUT 2021-07-15 05:48:33.987233
我进一步验证了问题确实是 predicate
没有通过将 timeout
更改为 15 来不断检查,它再次只检查 15 之后的 predicate
结果秒。
有没有办法让 predicate
经常检查这里?不是 while True
忙等待,因为它会占用 CPU(并且永远不会通过代码审查)。或者 threading.Condition.wait_for
是去这里的正确方法吗?
Condition 对象的目的是同步两个或多个线程的activity。当 Thread-1 调用 Condition.wait
时,它就被阻塞了。因此,它不可能像您希望的那样检查谓词何时变为真。相反,它必须等待 Thread-2 做一些可能导致谓词变为真的事情。在那一刻,Thread-2 应该通知 Condition 对象。对 notify
的调用导致 Thread-1 唤醒并检查谓词。如果谓词现在为真,Thread-1 继续执行;否则它会再次阻塞。
文档中是这样说的:
》忽略超时特性,调用该方法大致等同于这样写:
while not predicate():
cv.wait()
"
如果包含超时值,Thread-1 会在超时间隔后唤醒,而不管另一个线程是否调用了 notify。正如您观察到的那样,这会导致对谓词进行检查。
如果您想以合理的频率检查谓词,请提供足够短的超时时间或 确保另一个线程在适当的时间发出通知调用。
但是如果您不使用它来同步两个或多个线程,Condition 是错误的工具。如果你需要一个紧密的循环,写一个紧密的循环。