繁体   English   中英

Python:有没有一种线程安全的方法来知道lock.acquire()是否已被阻止(并继续阻止)?

[英]Python: Is there a thread safe way to know if lock.acquire() has blocked (and continue blocking)?

我正在为我的REST服务编写API库。 在某些时候,访问令牌将需要更新。 我正在尝试实现一种线程安全的方法来执行此操作,因此即使多个线程可能希望同时更新它,也仅发送一个更新请求。

这是我的代码的简化版本:

import requests

class Api():
    def _renew(self):
        # send a request which renews token in self._headers

    def do_something(self, url, params=None):
        r = requests(url, params=params, headers=self._headers)
        if r.status_code == 401 and r.json()['error'] == 'Token expired':
             # renew the access token
             self._renew()
             # repeat request with updated headers
             r = requests(url, params=params, headers=self._headers)
        return r.json()

我需要知道当前的续订请求是否正在进行。 我的想法是这样编写续订功能:

def _renew(self):
    lock.acquire()
    # i want to check here if the lock.acquire() call blocked
    # the thread and return immediately if it has
    try:
        # send a request to renew token header in self._headers
    finally:
        lock.release()

我希望其他线程可以调用do_something() (随后是_renew() )方法,直到第一个真正更新令牌并使其他人使用它的结果为止。

我怎么知道我的lock.acquire()调用是否被阻止?

在调用acquire() lock.locked()之前检查lock.locked()的结果不是线程安全的,有时有多个线程向服务器发送更新请求。

您可以调用lock.acquire(False)进行无阻塞调用,并使用返回值确定是否已获取锁。 看起来像这样:

def _renew(self):
    # calling when the lock is already acquired
    # will not block and return False
    if not lock.acquire(False):
        event.wait()
        return
    # else we acquired the lock 
    event.clear()
    try:
        # send a request to renew token header in self._headers
    finally:
        event.set()
        lock.release()

请参阅python 的threading-docs

另一种方法是将令牌包装在另一个类中:

from threading import Event, RLock

class Token:
    _internal = RLock()
    _marker = False
    def __init__(self):
        # TODO set header
        self._header = None

    def _renew(self):
        # TODO refresh the header
        pass

    def get(self):
        with self._internal:
            if self._marker:
                self._renew()
                self._marker = False
            return self._header

    # Marks the header to be refreshed at the next get()
    def set_renew(self):
        with self._internal:
            self._marker = True

这具有几个优点。 首先,令牌由自己负责。 在最佳环境中,它只会在需要时刷新自身,而不会被其他类刷新。 这应该在Token#get(self) 这也通过将所有get调用包装到锁中来解决线程安全问题,从而防止不必要的修改。

暂无
暂无

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

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