英文:
Concurrency Limiting with Semaphore, Why do I have to free up the buffer first?
问题
为什么只有在<-sem之前的results<-msg时,这段代码才能正常工作?我以为<-sem会释放缓冲区以供新的子例程使用。除此之外,有没有更好的方法来从goroutine中返回函数的结果?
从逻辑上讲,我想这样做,但是除非<-sem在results<-msg之前,否则它不起作用。
以下是你的代码:
package main
import (
"fmt"
"strconv"
"time"
"math/rand"
)
var intSlice = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
func printer(account int) string {
n := rand.Intn(1)
fmt.Printf("Sleeping %d seconds...\n", n)
time.Sleep(time.Duration(n)*time.Second)
return "Account Done " + strconv.Itoa(account)
}
func main() {
threads := 2
results := make(chan string, threads)
sem := make(chan bool, threads)
for _, account := range intSlice {
sem <- true //block
go func(account int) {
var msg = printer(account)
defer func() { <-sem; results<-msg }()
}(account)
}
for i := 0; i < cap(sem); i++ {
sem <- true
}
for i := 0; i < len(intSlice); i++ {
select {
case msg1 := <-results:
fmt.Println("received", msg1)
}
}
}
请注意,我只翻译了你提供的代码部分,其他部分保持原样。
英文:
Why will this code only work if <-sem; before results<-msg;? I thought <-sem frees up the buffer for a new subroutine. Apart from that is there a better way to return the result from a function within a go routine?
Logically I want to do this, but it doesnt work unless <-sem is above results<-msg.
var msg = printer(account)
results<-msg;
<-sem;
Here's my code:
package main
import (
"fmt"
"strconv"
"time"
//"runtime"
"math/rand"
)
var intSlice = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
func printer(account int) string {
n := rand.Intn(1)
fmt.Printf("Sleeping %d seconds...\n", n)
time.Sleep(time.Duration(n)*time.Second)
return "Account Done " + strconv.Itoa(account)
}
func main() {
threads := 2
results := make(chan string, threads)
sem := make(chan bool, threads)
for _, account := range intSlice {
sem <- true //block
go func(account int) {
var msg = printer(account)
defer func() { <-sem; results<-msg; }()
}(account)
}
for i := 0; i < cap(sem); i++ {
sem <- true
}
for i := 0; i < len(intSlice); i++ {
select {
case msg1 := <-results:
fmt.Println("received", msg1)
}
}
}
答案1
得分: 2
所以,sem
通道使用长度为2
的缓冲区进行初始化。
这使得程序可以在阻塞之前在该通道中推送两次,即在sem <- true //block
之前。
要从通道中释放一个空间,你需要在完成作业后使用<-sem
读取一个值,这意味着现在其他人可以再次推送到通道并在sem <- true //block
中继续执行。
从逻辑上讲,我想这样做,但是除非
<-sem
在results<-msg
之上,否则它不起作用。
var msg = printer(account) results<-msg; <-sem;
你不能这样写,因为你在results<-msg
处阻塞。由于results
尚未被读取,没有任何东西可以使这些指令继续执行。
实际上发生的是,在单独的例程中,你在results<-msg
处积累了多达len(sem)
个例程,它们在len(results)
处阻塞。它们将在达到循环for i := 0; i < len(intSlice); i++ {
时解开,但是它们不会解开,因为main
在sem <- true //block
处阻塞,等待那些在堆栈上的例程使用<-sem
释放空间。
英文:
so, the sem
channel is initialized with a buffer of len=2
This allows for the program to push twice in this channel, before blocking in sem <- true //block
.
To free a room from the channel, you read a value with <-sem
once a job is done, which means that by now, someone else can push again to the channel and move on in sem <- true //block
.
> Logically I want to do this, but it doesnt work unless <-sem is above
> results<-msg.
>
> var msg = printer(account)
> results<-msg;
> <-sem;
you can not write this because you are blocking at results<-msg
. As results
is not yet consumed by a reader, nothing allows for those instructions to move forward.
what happens really is that you are accumulating up to len(sem)
routines on the stack blocking on up to len(results)
at results <- msg
in a separate routine.
They would unwind when you reach that loop for i := 0; i < len(intSlice); i++ {
, but they don't because main
blocks at sem <- true //block
waiting for those on-stack routines to free room using <-sem
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论