试图在golang截止日期之前获得一把锁?

A C*_*rse 0 mutex timeout go

如何立即尝试仅获取一个类似于互斥锁的锁,要么立即中止操作(如TryLock在其他实现中所做的那样),要么观察某种形式的期限(基本上是LockBefore)?

我现在可以想到2种情况,这将对您大有帮助,并且我正在寻找某种解决方案。第一个是:占用大量CPU的服务,该服务接收对延迟敏感的请求(例如,Web服务)。在这种情况下,您可能想要执行类似下面的RPCService示例的操作。可以将其实现为工作队列(带有通道和填充),但是在这种情况下,衡量和利用所有可用CPU变得更加困难。也可以接受的是,当您获得锁时,您的代码可能已经超过了最后期限,但这不是理想的选择,因为它浪费了一些资源,并且意味着我们无法做类似“性能下降的临时任务”的事情。响应”。

    /* Example 1: LockBefore() for latency sensitive code. */
    func (s *RPCService) DoTheThing(ctx context.Context, ...) ... {
      if s.someObj[req.Parameter].mtx.LockBefore(ctx.Deadline()) {
        defer s.someObj[req.Parameter].mtx.Unlock()
        ... expensive computation based on internal state ...
      } else {
        return s.cheapCachedResponse[req.Parameter]
      }
    }
Run Code Online (Sandbox Code Playgroud)

另一种情况是,当您有一堆应该被触摸但可能被锁定的对象,并且应该在一定时间内完成触摸的位置(例如,更新某些统计信息)。在这种情况下,您也可以使用LockBefore()或某些形式的TryLock(),请参见下面的统计信息示例。

    /* Example 2: TryLock() for updating stats. */
    func (s *StatsObject) updateObjStats(key, value interface{}) {
      if s.someObj[key].TryLock() {
        defer s.someObj[key].Unlock()
        ... update stats ...
        ... fill in s.cheapCachedResponse ...
      }
    }

    func (s *StatsObject) UpdateStats() {
      s.someObj.Range(s.updateObjStats)
    }
Run Code Online (Sandbox Code Playgroud)

为了易于使用,我们假设在上述情况下,我们正在谈论相同的s.someObj。任何对象都可能长时间被DoTheThing()操作阻止,这意味着我们想在updateObjStats中跳过它。另外,我们希望确保在DoTheThing()中返回廉价响应,以防无法及时获取锁定。

不幸的是,仅sync.Mutex独家具有Lock()Unlock()函数。无法获得潜在的锁。有一些简单的方法可以做到这一点吗?我是从完全错误的角度来解决此类问题吗,有没有其他解决方案,更“可行”了?还是要解决这些问题,是否必须实现自己的Mutex库?我知道问题6123似乎暗示没有问题,而我处理这些问题的方式完全不合时宜。

Cer*_*món 7

使用缓冲区大小为1的通道作为互斥体。

l := make(chan struct{}, 1)
Run Code Online (Sandbox Code Playgroud)

锁:

l <- struct{}{}
Run Code Online (Sandbox Code Playgroud)

开锁:

<-l
Run Code Online (Sandbox Code Playgroud)

尝试锁定:

select {
case l <- struct{}{}:
    // lock acquired
    <-l
default:
    // lock not acquired
}
Run Code Online (Sandbox Code Playgroud)

尝试超时:

select {
case l <- struct{}{}:
    // lock acquired
    <-l
case <-time.After(time.Minute):
    // lock not acquired
}
Run Code Online (Sandbox Code Playgroud)


Eli*_*sky 6

我认为您在这里问了几件不同的事情:

  1. 标准库中是否存在此功能?不,事实并非如此。您可能可以在其他地方找到实现 - 这可以使用标准库(例如原子)来实现。

  2. 为什么标准库中不存在此功能:您在问题中提到的问题是一个讨论。go-nuts 邮件列表上也有几位 Go 代码开发人员参与的讨论:链接 1链接 2。通过谷歌搜索很容易找到其他讨论。

  3. 我怎样才能设计我的程序,这样我就不需要这个了?

(3) 的答案更加微妙,取决于您的具体问题。你的问题已经说了

可以将其实现为工作队列(带有通道和其他内容),但在这种情况下,衡量和利用所有可用 CPU 会变得更加困难

没有详细说明为什么与检查互斥锁状态相比,利用所有 CPU 会更困难。

在 Go 中,只要锁定方案变得不平凡,您通常就需要通道。它不应该更慢,而且应该更易于维护。