简体   繁体   English

在python中暂时释放一个锁(如果已持有)

[英]Release a lock temporarily if it is held, in python

I have a bunch of different methods that are not supposed to run concurrently, so I use a single lock to synchronize them. 我有一堆不应该同时运行的不同方法,因此我使用一个锁来同步它们。 Looks something like this: 看起来像这样:

selected_method = choose_method()
with lock:
    selected_method()

In some of these methods, I sometimes call a helper function that does some slow network IO. 在这些方法中的某些方法中,有时我会调用一个执行一些缓慢的网络IO的辅助函数。 (Let's call that one network_method() ). (让我们调用一个network_method() )。 I would like to release the lock while this function is running, to allow other threads to continue their processing. 我想在此函数运行时释放锁,以允许其他线程继续其处理。

One way to achieve this would be by calling lock.release() and lock.acquire() before and after calling the network method. 实现此目的的一种方法是在调用网络方法之前和之后调用lock.release()和lock.acquire()。 However, I would prefer to keep the methods oblivious to the lock, since there are many of them and they change all the time. 但是,我宁愿使方法不被锁定,因为它们有很多而且它们随时都在变化。

I would much prefer to rewrite network_method() so that it checks to see whether the lock is held, and if so release it before starting and acquire it again at the end. 我更喜欢重写network_method()以便它检查是否持有该锁,如果是,则在启动之前将其释放,最后再获取它。

Note that network_method() sometimes gets called from other places, so it shouldn't release the lock if it's not on the thread that holds it. 请注意,有时会从其他地方调用network_method() ,因此,如果它不在持有该锁的线程上,则不应释放该锁。

I tried using the locked() method on the Lock object, but that method only tells me whether the lock is held, not if it is held by the current thread. 我尝试在Lock对象上使用locked()方法,但是该方法仅告诉我是否持有锁,而不告诉我当前线程是否持有锁。

By the way, lock is a global object and I'm fine with that. 顺便说一句,锁是一个全局对象,对此我很好。

I would much prefer to rewrite network_method() so that it checks to see whether the lock is held, and if so release it before starting and acquire it again at the end. 我更喜欢重写network_method(),以便它检查是否持有该锁,如果是,则在启动之前将其释放,最后再获取它。

Note that network_method() sometimes gets called from other places, so it shouldn't release the lock if it's not on the thread that holds it. 请注意,有时会从其他地方调用network_method(),因此,如果它不在持有该锁的线程上,则不应释放该锁。

This just sounds like entirely the wrong thing to do :( 这听起来完全是错误的事情:(

For a start, it's bad to have a function that sometimes has some other magical side-effect depending on where you call it from. 首先,根据您从何处调用某个函数有时会产生一些其他神奇的副作用是很不好的。 That's the sort of thing that is a nightmare to debug. 那是调试的噩梦。

Secondly, a lock should have clear acquire and release semantics. 其次,锁应具有清晰的获取和释放语义。 If I look at code that says "lock(); do_something(); unlock();" 如果我看写的代码是“ lock(); do_something(); unlock();” then I expect it to be locked for the duration of do_something(). 那么我希望它在do_something()期间被锁定。 In fact, it is also telling me that do_something() requires a lock. 实际上,这还告诉我do_something()需要锁定。 If I find out that someone has written a particular do_something() which actually unlocks the lock that I just saw to be locked, I will either (a) fire them or (b) hunt them down with weapons, depending on whether I am in a position of seniority relative to them or not. 如果我发现有人写了一个特定的do_something()可以真正解锁我刚刚看到的锁,我将(a)发射它们或(b)使用武器追捕它们,具体取决于我是否在是否相对于他们有资历。

By the way, lock is a global object and I'm fine with that. 顺便说一句,锁是一个全局对象,对此我很好。

Incidentally, this is also why globals are bad. 顺便说一句,这也是为什么全局变量不好的原因。 If I modify a value, call a function, and then modify a value again, I don't want that function in the middle being able to reach back out and modify this value in an unpredictable way. 如果我修改一个值,调用一个函数,然后再次修改一个值,我不希望中间的那个函数能够以一种无法预测的方式伸出援手并修改该值。

My suggestion to you is this: your lock is in the wrong place, or doing the wrong thing, or both. 我对您的建议是:您的锁在错误的位置,或做错事,或两者兼而有之。 You say these methods aren't supposed to run concurrently, but you actually want some of them to run concurrently. 您说这些方法不应该并发运行,但实际上您希望其中一些并发运行。 The fact that one of them is "slow" can't possibly make it acceptable to remove the lock - either you need the mutual exclusion during this type of operation for it to be correct, or you do not. 其中之一“很慢”的事实可能无法使人们满意地删除锁-在这种类型的操作过程中您需要相互排斥才能使锁正确,或者您不需要。 If the slower operation is indeed inherently safe when the others are not, then maybe it doesn't need the lock - but that implies the lock should go inside each of the faster operations, not outside them. 如果较慢的操作在本质上是安全的,而其他操作则不需要,则可能不需要该锁-但这意味着该锁应位于每个较快操作的内部,而不是外部。 But all of this is dependent on what exactly the lock is for. 但是,所有这些都取决于锁的确切用途。

Why not just do this? 为什么不这样做呢?

with lock:
    before_network()
do_network_stuff()
with lock:
    after_network()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM