Python 2.7 - 如何防止断言释放锁

时间:2017-08-31 07:27:26

标签: python multithreading python-2.7 assertion

当我的程序遇到断言失败时,我不希望断言库执行导致程序进一步发展的事情,而不是没有断言失败。但这正是内置assert似乎所做的:它引发了一个异常,它会释放锁。

例如,请考虑以下程序。

import threading
import time

lock = threading.Lock()

class Thread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.start()
    def run(self):
        with lock:
            time.sleep(0.2)
            print "ASSERTION ON NEXT LINE"
            assert False

            # Were it not for the assert, 
            # This thread would hold the lock for a while longer.
            time.sleep(1.0)
Thread()        


time.sleep(0.1)
with lock:
    print "*** Main Thread ***"

断言导致锁被释放,这导致主线程获得断言失败和回溯之间的锁定。结果,输出为:

ASSERTION ON NEXT LINE
*** Main Thread ***
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "so.py", line 14, in run
    assert False
AssertionError

这是非常不受欢迎的,因为在追溯之前会打印*** Main Thread ***。这很容易误导人们认为*** Main Thread ***在生成异常之前获得了锁。

我知道我们可以编写自己的断言函数来调用os._exit()而不是提出断言。我想知道的是,标准包装中是否已有类似的内容。

3 个答案:

答案 0 :(得分:1)

如果您不想发布lock,则必须在with lock:内发现异常:

with lock:
    try:
        time.sleep(0.2)
        print "ASSERTION ON NEXT LINE"
        assert False
    except Exception:
        print "there was an exception"
    while True:
        pass

答案 1 :(得分:0)

如果我们使用assert并且失败则会引发断言错误。因为断言仅用于执行此操作(中断/停止流程)。我可以想到将它与Queue同步。

import time
import threading 
from Queue import Queue



q = Queue()
# code here
class MyThread(threading.Thread):
    def run(self):
        # do stuff
        print "ASSERTION ON NEXT LINE" 
        q.put(True)
        # do other stuff

# code here
mt = MyThread()
mt.start()

try:
    assert q.get()
finally:
    mt.join()

答案 2 :(得分:0)

谢谢大家的贡献。我将主要以丹尼尔的答案为基础。我相信最好的答案取决于锁内有多少代码。如果你有一个很大的函数调用,那么

with lock:
    try:
        deep_complicated_function()
    except Exception:
        print "there was an exception"
        print '\n'.join(traceback.format_stack()[:-1])
        os._exit(1)
    while True:
        pass

是最好的,因为它使您有机会在一个构造中为大量异常情况提供处理程序。

然而,这对于一次性断言的输入太多,例如:

with lock:
   quick_update()
   assert property()

这些情况需要更方便的东西,例如:

def Assert(cond, msg = "Assertion failed."):
    if not cond:
        print msg
        print '\n'.join(traceback.format_stack()[:-1])
        os._exit(1)

这将停止该过程,这简化了调试(如问题中所讨论的)。要在nose和其他测试工具中使用,请通过多处理API启动主程序,并在退出代码不为0时生成异常。