英文:
Deadlock when running two go routine
问题
我现在是你的中文翻译助手,以下是你要翻译的内容:
我现在在业余时间学习Golang,并尝试在线进行一些样例考试来测试我所学到的知识。我遇到了这个编程考试任务,但是我似乎无法使其正常运行,而是遇到了"fatal error: all goroutines are asleep - deadlock!"的错误。有人可以帮忙看看我在这里做错了什么吗?
func executeParallel(ch chan<- int, done chan<- bool, functions ...func() int) {
ch <- functions[1]()
done <- true
}
func exampleFunction(counter int) int {
sum := 0
for i := 0; i < counter; i++ {
sum += 1
}
return sum
}
func main() {
expensiveFunction := func() int {
return exampleFunction(200000000)
}
cheapFunction := func() int {return exampleFunction(10000000)}
ch := make(chan int)
done := make(chan bool)
go executeParallel(ch, done, expensiveFunction, cheapFunction)
var isDone = <-done
for result := range ch {
fmt.Printf("Result: %d\n", result)
if isDone {
break;
}
}
}
英文:
Im studying Golang now on my freetime and I am trying sample exams online to test what i learned,
I came about this coding exam task but I cant seem to make it work/run without a crash,
im getting fatal error: all goroutines are asleep - deadlock! error, can anybody help what I am doing wrong here?
func executeParallel(ch chan<- int, done chan<- bool, functions ...func() int) {
ch <- functions[1]()
done <- true
}
func exampleFunction(counter int) int {
sum := 0
for i := 0; i < counter; i++ {
sum += 1
}
return sum
}
func main() {
expensiveFunction := func() int {
return exampleFunction(200000000)
}
cheapFunction := func() int {return exampleFunction(10000000)}
ch := make(chan int)
done := make(chan bool)
go executeParallel(ch, done, expensiveFunction, cheapFunction)
var isDone = <-done
for result := range ch {
fmt.Printf("Result: %d\n", result)
if isDone {
break;
}
}
}
答案1
得分: 1
你的executeParallel
函数在提供少于2个函数时会引发恐慌,并且只会运行第二个函数:
ch <- functions[1]() // 如果提供的函数少于2个,则运行时会引发恐慌
我认为它应该像这样:并行运行所有输入函数,并获取第一个结果。
for _, fn := range functions {
fn := fn // 以便每次迭代/ goroutine 都能得到正确的值
go func() {
select {
case ch <- fn():
// 第一个(最快的工作线程)获胜
default:
// 其他工作线程的结果被丢弃(如果读取器尚未读取结果)
// 这样可以确保我们不会泄漏 goroutine,因为读取器只从通道中读取一个结果
}
}()
}
因此,不需要done
通道-因为我们只需要读取唯一(最快)的结果:
ch := make(chan int, 1) // 足够大以捕获一个结果-即使读取器尚未读取
executeParallel(ch, expensiveFunction, cheapFunction)
fmt.Printf("Result: %d\n", <-ch)
链接:https://play.golang.org/p/skXc3gZZmRn
英文:
Your executeParallel
function will panic if less than 2 functions are provided - and will only run the 2nd function:
ch <- functions[1]() // runtime panic if less then 2 functions
I think it should look more like this: running all input functions in parallel and grabbing the first result.
for _, fn := range functions {
fn := fn // so each iteration/goroutine gets the proper value
go func() {
select {
case ch <- fn():
// first (fastest worker) wins
default:
// other workers results are discarded (if reader has not read results yet)
// this ensure we don't leak goroutines - since reader only reads one result from channel
}
}()
}
As such there's no need for a done
channel - as we just need to read the one and only (quickest) result:
ch := make(chan int, 1) // big enough to capture one result - even if reader is not reading yet
executeParallel(ch, expensiveFunction, cheapFunction)
fmt.Printf("Result: %d\n", <-ch)
答案2
得分: 0
package main
import "fmt"
func executeParallel(ch chan<- int, done chan<- struct{}, functions ...func() int) {
// 只有在函数数量大于1时才执行第二个函数[1]。
if len(functions) > 1 {
ch <- functions[1]()
}
// 关闭done通道以通知for-select跳出循环并返回主函数。
close(done)
}
// example返回[0..counter-1]的迭代次数
func example(counter int) int {
sum := 0
for i := 0; i < counter; i++ {
sum += 1
}
return sum
// 注意(SS):这个函数可以直接返回"counter-1",以避免上面不必要的计算。
}
func main() {
var (
cheap = func() int { return example(10000000) }
expensive = func() int { return example(200000000) }
ch = make(chan int)
done = make(chan struct{})
)
// executeParallel接受ch、done通道,后跟可变数量的函数,
// 其中第二个即索引为1的函数在一个单独的goroutine中执行,
// 然后将其发送到ch通道,然后由下面的for-select接收器接收。
go executeParallel(ch, done, expensive, cheap)
for {
select {
// 等待done通道被发送数据或关闭。
case <-done:
return
// 从ch接收数据(如果有数据被发送到ch)。
case result := <-ch:
fmt.Println("Result:", result)
}
}
}
我已经对代码进行了注释,以便更容易理解。由于您没有提供实际问题,所以逻辑可能仍然有误。
英文:
package main
import "fmt"
func executeParallel(ch chan<- int, done chan<- struct{}, functions ...func() int) {
// Only execute the second function [1], if available.
if len(functions) > 1 {
ch <- functions[1]()
}
// Close the done channel to signal the for-select to break and the main returns.
close(done)
}
// example returns the number of iterations for [0..counter-1]
func example(counter int) int {
sum := 0
for i := 0; i < counter; i++ {
sum += 1
}
return sum
// NOTE(SS): This function could just return "counter-1"
// to avoid the unnecessary calculation done above.
}
func main() {
var (
cheap = func() int { return example(10000000) }
expensive = func() int { return example(200000000) }
ch = make(chan int)
done = make(chan struct{})
)
// executeParallel takes ch, done channel followed by variable
// number of functions where on the second i.e., indexed 1
// function is executed on a separated goroutine which is then
// sent to ch channel which is then received by the for-select
// reciever below i.e., <-ch is the receiver.
go executeParallel(ch, done, expensive, cheap)
for {
select {
// Wait for something to be sent to done or the done channel
// to be closed.
case <-done:
return
// Keep receiving from ch (if something is sent to it)
case result := <-ch:
fmt.Println("Result:", result)
}
}
}
I have commented on the code so that it's understandable. As you didn't the actual question the logic could be still wrong.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论