with與async with

應(yīng)用場(chǎng)景:

  • 文件的讀寫
  • 數(shù)據(jù)庫(kù)的讀寫操作
  • Flask的上下文管理

上下文管理協(xié)議:當(dāng)使用with語(yǔ)句時(shí),解釋器會(huì)自動(dòng)調(diào)用 __enter__,__exit__

class Sample:
    def __enter__(self):
        print('enter')  #進(jìn)入資源
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')  #釋放資源
    def do_something(self):
        print('do something')

with Sample() as sample:   
    sample.do_something()

輸出

enter
do something
exit

進(jìn)入with語(yǔ)句,調(diào)用__enter__;退出with語(yǔ)句,調(diào)用__exit__

事實(shí)上sample并不是sample=Sample(),而是__enter__返回的對(duì)象,即如果__enter__沒有return,sample將為None。

exc_type:異常類型;exc_val:異常值;exc_tb:traceback。如果with語(yǔ)句中有異常發(fā)生,__exit__中會(huì)收集這些異常信息。

async with

async with的用法和with一樣,只是內(nèi)部使用__aenter____aexit__來定義上下文。這樣我們就能在上下文中使用異步編程。

class Lock(object):
    def __init__(self, redis_client, key="", ttl=60, timeout=30, interval=0.03, is_wait=True):
        """
        :param key:
        :param ttl: expire time(鎖最大過期時(shí)間) / s
        :param timeout: timeout(阻塞最大時(shí)間) / s
        :param interval: sleep interval(睡眠間隔) / s
        :return:
        Usage::

            with Lock('my_lock') as lock:
                pass
        """
        self.redis_client = redis_client
        self.key = f"redis:lock:{key}"
        self.ttl = ttl
        self.timeout = timeout
        self.interval = interval
        self.value = uuid.uuid1().hex
        self.is_wait = is_wait

    async def __aenter__(self):
        res, wait_times = await self.async_acquire()
        return wait_times

    async def __aexit__(self, exc_type, exc, tb):
        self.release()

    async def async_acquire(self):
        timeout = self.timeout
        wait_times = 0  # 嘗試獲取鎖的次數(shù)
        if timeout == 0:
            while True:
                wait_times += 1
                # redis操作理論上也需要改為異步,由于redis操作很快,暫時(shí)先用同步
                if self.redis_client.set(self.key, self.value, ex=self.ttl, nx=True):
                    return True, wait_times
                if not self.is_wait:  # 不等待鎖
                    raise TooFrequentException('Operation is too frequent')
                await asyncio.sleep(self.interval)
        else:
            while timeout >= 0:
                wait_times += 1
                if self.redis_client.set(self.key, self.value, ex=self.ttl, nx=True):
                    return True, wait_times
                timeout -= self.interval
                if not self.is_wait:  # 不等待鎖
                    raise TooFrequentException('Operation is too frequent')
                await asyncio.sleep(self.interval)
            raise LockTimeout("Timeout whilst waiting for lock")
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容