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

为什么我在main中使用goroutine时我的程序没有关闭?

为什么我在main中使用goroutine时我的程序没有关闭?

Go
GCT1015 2023-01-03 17:17:07
语境请仔细阅读代码中的注释。一切都在他们身上。如果您有使用经验discordgo完整的代码可以在这里找到:https ://github.com/telephrag/kubinka/tree/bug (查看包strg和main)添加 goroutine 命令处理程序也会停止正常工作。与数据库交互相关的所有内容(分别在 /deploy 和 /return 上存储和从数据库中删除)根本不起作用。用户只会收到“应用程序未响应”消息而不是正确的响应(请参阅以cmd_前缀开头的包)。package mainimport (    "context"    "fmt"    "log"    "os"    "os/signal"    "syscall"    "time"    "go.etcd.io/bbolt")/*  TO REPRODUCE:Start the program wait a few seconds and press ^C.Expect the case of program not shutting down after few attempts.*/func WatchExpirations(ctx context.Context, db *bbolt.DB, bkt string) error {    timeout := time.After(time.Second * 5)    for {        select {        case <-timeout:            tx, err := db.Begin(true)            if err != nil {                return fmt.Errorf("bolt: failed to start transaction")            }            bkt := tx.Bucket([]byte(bkt))            c := bkt.Cursor()            for k, v := c.First(); k != nil; k, v = c.Next() {                // do stuff with bucket...                fmt.Println(v) // check if v matches condition, delete if does                if err := tx.Commit(); err != nil { // BUG: commiting transaction in a loop                    tx.Rollback()                    return fmt.Errorf("bolt: failed to commit transaction: %w", err)                }                timeout = time.After(time.Second * 5)            }        case <-ctx.Done():            return ctx.Err()        }    }}func main() {    ctx, cancel := context.WithCancel(context.Background())    db, err := bbolt.Open("kubinka.db", 0666, nil)    if err != nil {        log.Panicf("failed to open db %s: %v", "kubinka.db", err)    }    if err = db.Update(func(tx *bbolt.Tx) error {        _, err := tx.CreateBucketIfNotExists([]byte("players"))        if err != nil {            return fmt.Errorf("failed to create bucket %s: %w", "players", err)        }        return nil    }); err != nil {        log.Panic(err)    }
查看完整描述

1 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

根据您的回购协议中的评论,问题似乎出在这里:

tx, err := db.Begin(true)

if err != nil {

   return fmt.Errorf("bolt: failed to start transaction")

}

bkt := tx.Bucket([]byte(bkt))

c := bkt.Cursor()

for k, v := c.First(); k != nil; k, v = c.Next() {

    // do stuff with bucket...

    fmt.Println(v) // check if v matches condition, delete if does


    if err := tx.Commit(); err != nil { // BUG: commiting transaction in a loop

        tx.Rollback()

        return fmt.Errorf("bolt: failed to commit transaction: %w", err)

    }

    timeout = time.After(time.Second * 5)

}

循环可以迭代 0 次。

  • 如果没有迭代 -tx不提交timeout也不重置(因此case <-timeout:不会再次触发)。

  • 如果有多次迭代 - 您将尝试tx.Commit()多次(错误)。

这可能导致了您看到的问题;bolt Close功能:_

关闭释放所有数据库资源。在关闭数据库之前必须关闭所有事务。

因此,如果有一个事务运行Close块直到完成(内部螺栓在事务开始时锁定互斥锁并在完成时释放它)。

解决方案是确保事务始终关闭(并且只关闭一次)。



查看完整回答
反对 回复 2023-01-03
  • 1 回答
  • 0 关注
  • 74 浏览
慕课专栏
更多

添加回答

举报

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