英文:
Why does the behavior of chan change after I use gorm to connect to the database
问题
一个正常的例子是这样的:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
func() {
time.Sleep(1)
ch <- 1
}()
fmt.Println(<-ch)
}
输出应该是:
# go run test.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main.func1(...)
/root/test.go:17
main.main()
/root/test.go:18 +0x47
exit status 2
但是当我添加连接数据库的代码时,像这样:
package main
import (
"fmt"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(mysql.Open("dsn"))
fmt.Printf("%v, %s\n", db, err)
ch := make(chan int)
func() {
time.Sleep(1)
ch <- 1
}()
fmt.Println(<-ch)
}
它不会报错,而是一直阻塞,输出结果是(我用Ctrl+C结束了它):
# go run test.go
&{0xc00015c510 <nil> 0 0xc00016c380 1}, %!s(<nil>)
^Csignal: interrupt
有人可以帮助我吗,谢谢。
英文:
A normal example is this:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
func() {
time.Sleep(1)
ch <- 1
}()
fmt.Println(<-ch)
}
The output should be:
# go run test.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main.func1(...)
/root/test.go:17
main.main()
/root/test.go:18 +0x47
exit status 2
But when I add the code to connect to the database like this:
package main
import (
"fmt"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(mysql.Open("dsn"))
fmt.Printf("%v, %s\n", db, err)
ch := make(chan int)
func() {
time.Sleep(1)
ch <- 1
}()
fmt.Println(<-ch)
}
It doesn't report an error, it keeps blocking, the output is(I ended it with ctrl+c):
# go run test.go
&{0xc00015c510 <nil> 0 0xc00016c380 1}, %!s(<nil>)
^Csignal: interrupt
Can anyone help me, thanks.
答案1
得分: 1
在连接的数据库情况下,它不会报告“所有goroutine都处于休眠状态”,因为并非所有goroutine都处于休眠状态。
gorm和db会启动它们自己的goroutine,这些goroutine在等待发送接收或执行其他操作。
如果在这两种情况下都执行ctrl+\
,这些goroutine将会显示出来。
-
未连接数据库:
goroutine 0 [空闲]: runtime.epollwait()
/usr/lib/golang/src/runtime/sys_linux_amd64.s:699 +0x20 runtime.netpoll(0xc000032500?)
/usr/lib/golang/src/runtime/netpoll_epoll.go:126 +0xdc -
已连接数据库:
goroutine 0 [空闲]:
runtime.futex()
/usr/lib/golang/src/runtime/sys_linux_amd64.s:552 +0x21
runtime.futexsleep(0x10000000000?, 0xcb927f8?, 0x7fffc45f8fa8?)
/usr/lib/golang/src/runtime/os_linux.go:66 +0x36
goroutine 1 [通道发送]:
main.main.func1(...)
goroutine 19 [select]:
database/sql.(*DB).connectionOpener(0xc00019ea90, {0x81af60, 0xc0001972c0})
goroutine 20 [select]:
github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher.func1()
英文:
It does not report all goroutines are asleep
in case of connected DB because all goroutines are not asleep.
gorm and db start their own goroutines that are waiting to send receive, doing other stuff.
if you do a ctrl+\
in both cases these goroutines will be shown
1 No DB connected
goroutine 0 [idle]: runtime.epollwait()
/usr/lib/golang/src/runtime/sys_linux_amd64.s:699 +0x20 runtime.netpoll(0xc000032500?)
/usr/lib/golang/src/runtime/netpoll_epoll.go:126 +0xdc
- DB connected
goroutine 0 [idle]:
runtime.futex()
/usr/lib/golang/src/runtime/sys_linux_amd64.s:552 +0x21
runtime.futexsleep(0x10000000000?, 0xcb927f8?, 0x7fffc45f8fa8?)
/usr/lib/golang/src/runtime/os_linux.go:66 +0x36
goroutine 1 [chan send]:
main.main.func1(...)
goroutine 19 [select]:
database/sql.(*DB).connectionOpener(0xc00019ea90, {0x81af60, 0xc0001972c0})
goroutine 20 [select]:
github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher.func1()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论