为了账号安全,请及时绑定邮箱和手机立即绑定

Golang 睡眠线程而不是忙于等待

Golang 睡眠线程而不是忙于等待

Go
jeck猫 2022-05-10 13:33:42
我正在编写Leslie Lamport's Bakery algorithm的 Go 实现,它有忙自旋等待来处理最大数量的线程。我正在编写一个 go 函数,除非满足特殊条件,否则该函数不应继续执行。到目前为止,我的代码如下所示:func acquireLock() {    ...    for specialConditionIsFalse {    }    ...}有没有更有效的方法来停止处理这个线程?
查看完整描述

2 回答

?
holdtom

TA贡献1805条经验 获得超10个赞

这里有几点值得注意:

  1. goroutines 不是线程。没有“goroutine 数量”,系统中的 goroutine 数量也没有固定的上限。1 可以修改 Bakery 算法以处理动态创建的线程(使用列表或映射,如 Wikipedia 页面上的 Java 示例),但对每个“线程”有一个唯一 ID 的强烈要求,这使得这不是一个一般而言,Go 的好主意。(您可以依次使用实现类似线程行为的包来解决这个问题,包括线程 ID。)

  2. 正如维基百科页面所指出的:

    Lamport 的面包店算法假设一个顺序一致性内存模型。很少有(如果有的话)语言或多核处理器实现这样的内存模型。因此,算法的正确实现通常需要插入栅栏来禁止重新排序。

    这意味着您将需要使用该sync/atomic包,这违背了编写自己的锁定的目的。

有了这两个巨大的警告,你可以调用runtime.Gosched()你会调用 POSIX 样式yield()函数的地方,或者你可以使用一个通道来表示有人“离开了面包店”,因此轮到下一个用户了。但是渠道本身会完成您需要的所有互斥。一个简化的特定于 Go 的非 Lamport 面包店算法是微不足道的(但以下所有内容都未经测试):

var takeANumber chan int64

var currentlyServing int64


init() {

    takeANumber = make(chan int64)

    go giveNumbers()

}


// giveNumbers hands out ever-increasing ticket numbers

func giveNumbers() {

    for int64 i := 0;; i++ {

        takeANumber <- i

    }

}


// WaitTurn gets a ticket, then waits until it is our turn.  You can

// call this "Lock" if you like.

func WaitTurn() int64 {

    ticket := <-takeANumber

    for atomic.LoadInt64(&currentlyServing) < ticket {

        runtime.Gosched()

    }

    return ticket

}


// ExitBakery relinquishes our ticket, allowing the next user to proceed.

func ExitBakery(ticket int64) {

    atomic.StoreInt64(&currentlyServing, ticket + 1)

}

将其修改为使用两个通道,以便该WaitTurn功能更有效,留作练习。(当然,除了作为练习之外,没有理由一开始就使用这些代码。)


1您可以设置运行时限制,但如果您调用任何阻塞系统调用,系统无论如何都会产生额外的 goroutine。阻塞的系统调用集以及何时调用它们取决于运行时,因此您无法对此进行真正的控制,至少在不编写特定于平台的代码的情况下是无法控制的。


查看完整回答
反对 回复 2022-05-10
?
ibeautiful

TA贡献1993条经验 获得超5个赞

在当前版本中,goroutine 不是可抢占的。这意味着如果你有一个紧密循环的 goroutine,那么这个 goroutine 不会将它正在运行的线程让给其他 goroutine。有时这可能意味着没有其他 goroutine 将永远运行。

不要像这样忙着等待,而是使用一个频道:

<-specialCondition
// Do stuff

并在特殊情况发生时关闭它。

您也可以尝试使用 a sync.Cond,但您可以使用通道执行条件变量所做的所有事情。



查看完整回答
反对 回复 2022-05-10
  • 2 回答
  • 0 关注
  • 162 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信