如何检测占用锁的goroutine?
How to detect the goroutine that occupies the lock?
我用 Echo
创建了一个 HTTP 服务器并存储数据使用 storm
和这样的数据模型:
project1(bucket)
device_type_1(bucket)
device_1(kv)
device_2(kv)
device_type_2(bucket)
device_1(kv)
device_2(kv)
project2(bucket)
...
除了更新数据库,收到HTTP请求后还有一些其他的事情要做,所以我使用这样的事务:
tx, err := db.Begin(true)
if err != nil {
return
}
defer tx.Rollback()
// for simplicity
projectBkt := tx.From("project1")
projectBkt.Save(&project)
// other things
.......
if err := tx.Commit(); err != nil {
return
}
bolt事务提交时锁等待的概率很高,栈是这样的:
goroutine 53 [semacquire, 5 minutes]:
sync.runtime_SemacquireMutex(0xc000002560, 0x16a7f00, 0x0)
C:/Go/src/runtime/sema.go:71 +0x4e
sync.(*RWMutex).Lock(0xc000002558)
C:/Go/src/sync/rwmutex.go:103 +0xc0
go.etcd.io/bbolt.(*DB).mmap(0xc0000023c0, 0x20000, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:246 +0x65
go.etcd.io/bbolt.(*DB).allocate(0xc0000023c0, 0x1, 0x0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:846 +0x24b
go.etcd.io/bbolt.(*Tx).allocate(0xc000e98fc0, 0x1, 0x0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:454 +0x79
go.etcd.io/bbolt.(*node).spill(0xc0001539d0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/node.go:368 +0x3f0
go.etcd.io/bbolt.(*Bucket).spill(0xc0001cb740, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:541 +0x73a
go.etcd.io/bbolt.(*Bucket).spill(0xc000e98fd8, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:508 +0x64f
go.etcd.io/bbolt.(*Tx).Commit(0xc000e98fc0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:163 +0x1bf
github.com/asdine/storm.(*node).Commit(0xc0001cb380, 0x0, 0x0)
D:/data/Go/pkg/mod/github.com/asdine/storm@v2.1.2+incompatible/transaction.go:46 +0x5c
.....
问题是如何检测占用锁的goroutine,以便检查整个操作顺序?
协程没有外部 ID。
根据设计,锁可以在一个 goroutine 中获取并在另一个 goroutine 中释放。因此,如果一个锁被持有,它不会被 由 一个 Goroutine 持有:任何人都可以解锁它,并且没有 ID 来记录谁锁定了它。
(因此,答案是仅使用提供的互斥锁,您看不到谁在霸占它。)
我用 Echo
创建了一个 HTTP 服务器并存储数据使用 storm
和这样的数据模型:
project1(bucket)
device_type_1(bucket)
device_1(kv)
device_2(kv)
device_type_2(bucket)
device_1(kv)
device_2(kv)
project2(bucket)
...
除了更新数据库,收到HTTP请求后还有一些其他的事情要做,所以我使用这样的事务:
tx, err := db.Begin(true)
if err != nil {
return
}
defer tx.Rollback()
// for simplicity
projectBkt := tx.From("project1")
projectBkt.Save(&project)
// other things
.......
if err := tx.Commit(); err != nil {
return
}
bolt事务提交时锁等待的概率很高,栈是这样的:
goroutine 53 [semacquire, 5 minutes]:
sync.runtime_SemacquireMutex(0xc000002560, 0x16a7f00, 0x0)
C:/Go/src/runtime/sema.go:71 +0x4e
sync.(*RWMutex).Lock(0xc000002558)
C:/Go/src/sync/rwmutex.go:103 +0xc0
go.etcd.io/bbolt.(*DB).mmap(0xc0000023c0, 0x20000, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:246 +0x65
go.etcd.io/bbolt.(*DB).allocate(0xc0000023c0, 0x1, 0x0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:846 +0x24b
go.etcd.io/bbolt.(*Tx).allocate(0xc000e98fc0, 0x1, 0x0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:454 +0x79
go.etcd.io/bbolt.(*node).spill(0xc0001539d0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/node.go:368 +0x3f0
go.etcd.io/bbolt.(*Bucket).spill(0xc0001cb740, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:541 +0x73a
go.etcd.io/bbolt.(*Bucket).spill(0xc000e98fd8, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:508 +0x64f
go.etcd.io/bbolt.(*Tx).Commit(0xc000e98fc0, 0x0, 0x0)
D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:163 +0x1bf
github.com/asdine/storm.(*node).Commit(0xc0001cb380, 0x0, 0x0)
D:/data/Go/pkg/mod/github.com/asdine/storm@v2.1.2+incompatible/transaction.go:46 +0x5c
.....
问题是如何检测占用锁的goroutine,以便检查整个操作顺序?
协程没有外部 ID。
根据设计,锁可以在一个 goroutine 中获取并在另一个 goroutine 中释放。因此,如果一个锁被持有,它不会被 由 一个 Goroutine 持有:任何人都可以解锁它,并且没有 ID 来记录谁锁定了它。
(因此,答案是仅使用提供的互斥锁,您看不到谁在霸占它。)