TSemaphore

TSemaphore 是具有事务语义的信号量,可用于控制对公共资源的访问。它拥有一定数量的许可证,并且可以获取或释放许可证。

创建一个 TSemaphore

创建一个具有 10 个许可证的 TSemaphore

import zio._
import zio.stm._

val tSemaphoreCreate: STM[Nothing, TSemaphore] = TSemaphore.make(10L)

获取一个许可证

一旦外部程序获得许可证,这会减少 TSemaphore 包含的剩余许可证数量。当用户想要访问受限共享资源时,就需要获取可:

import zio._
import zio.stm._

val tSemaphoreAcq: STM[Nothing, TSemaphore] = for {
  tSem <- TSemaphore.make(2L)
  _    <- tSem.acquire
} yield tSem

tSemaphoreAcq.commit

请注意,如果在信号量中没有剩余的许可证时,尝试获取许可证则具有阻塞的语意,直到有许可证为止。请注意,阻塞语义不会阻塞线程,只当有许可证被释放时系统才会尝试重试 STM 事务。

释放一个许可证

访问完共享资源后,必须释放许可证,以便其它第三方可以访问共享资源:

import zio._
import zio.stm._

val tSemaphoreRelease: STM[Nothing, TSemaphore] = for {
  tSem <- TSemaphore.make(1L)
  _    <- tSem.acquire
  _    <- tSem.release
} yield tSem

tSemaphoreRelease.commit

查询可用的许可证

您可以使用 available 查询在 TSemaphore 中的剩余许可数量:

import zio._
import zio.stm._

val tSemaphoreAvailable: STM[Nothing, Long] = for {
  tSem <- TSemaphore.make(2L)
  _    <- tSem.acquire
  cap  <- tSem.available
} yield cap

tSemaphoreAvailable.commit

上面的代码创建一个具有两个许可证的 TSemaphore,然后立刻获得但不释放一个许可。然后,“available” 将会报告仅剩一个许可证。

执行带有自动获取和释放功能的 STM 操作

您可以将任意在 TSemaphoreacquirerelease 许可证的 STM 操作,作为一个事务的一部分。与其:

import zio._
import zio.stm._

def yourSTMAction: STM[Nothing, Unit] = STM.unit

val tSemaphoreWithoutPermit: STM[Nothing, Unit] = 
  for {
    sem <- TSemaphore.make(1L)
    _   <- sem.acquire
    a   <- yourSTMAction
    _   <- sem.release
  } yield a

tSemaphoreWithoutPermit.commit

不如:

import zio._
import zio.stm._

val tSemaphoreWithPermit: STM[Nothing, Unit] = for {
  sem <- TSemaphore.make(1L)
  a   <- sem.withPermit(yourSTMAction)
} yield a

tSemaphoreWithPermit.commit

最佳实践是使用 withPermit 而不是直接使用 acquire 和 release,除非更复杂的,比如涉及多个 STM 动作,并且它们不以 acquire 作为事务的起点,也不以 release 作为终点的情况。

获取和释放多个许可证

使用 acquireNreleaseN 一次可以获取和释放若干个许可证:

import zio._
import zio.stm._

val tSemaphoreAcquireNReleaseN: STM[Nothing, Boolean] = for {
  sem <- TSemaphore.make(3L)
  _   <- sem.acquireN(3L)
  cap <- sem.available 
  _   <- sem.releaseN(3L)
} yield cap == 0

tSemaphoreAcquireNReleaseN.commit
Leave a Reply
Your email address will not be published.
*
*

BACK TO TOP