Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将对sqlite数据库的多个请求模拟为goroutine会导致随机恐慌_Sqlite_Go - Fatal编程技术网

将对sqlite数据库的多个请求模拟为goroutine会导致随机恐慌

将对sqlite数据库的多个请求模拟为goroutine会导致随机恐慌,sqlite,go,Sqlite,Go,我试图模拟从http.HandleFunc到函数的多个请求,该函数对sqlite数据库进行更改。我假设http.HandleFunc调用的函数实际上是goroutine。见下面的代码: package main import "fmt" import "time" import "code.google.com/p/go-sqlite/go1/sqlite3" import "crypto/rand" import "encoding/base64" func getrandomtext()

我试图模拟从http.HandleFunc到函数的多个请求,该函数对sqlite数据库进行更改。我假设http.HandleFunc调用的函数实际上是goroutine。见下面的代码:

package main
import "fmt"
import "time"
import "code.google.com/p/go-sqlite/go1/sqlite3"
import "crypto/rand"
import "encoding/base64" 

func getrandomtext() (string) {
    b := make([]byte, 12)
    rand.Read(b)
    en := base64.StdEncoding // or URLEncoding
    enclen := en.EncodedLen(len(b))
    d := make([]byte, enclen)
    en.Encode(d, b)
    returntext := string(d[:enclen])
    //fmt.Printf("getrandomtext() : '"+returntext+"'\n")
    return returntext
}

func main() {
    dbname := "multitasking.db"
    tablename := "multiwrite"
    defer time.Sleep(5000 * time.Millisecond)
    db, err := sqlite3.Open("file:"+dbname+"?file:locked.sqlite?cache=shared&mode=rwc")
    defer db.Close()
    if err != nil {
        fmt.Printf("failed to open database, error: " + err.Error() + "\n") 
        return
    } 
    err = db.Exec("DROP TABLE IF EXISTS "+tablename+";")
    if err != nil {
        fmt.Printf("error dropping table "+tablename+": "+err.Error()+"\n")
    }
    err = db.Exec("CREATE TABLE "+tablename+" (id INTEGER PRIMARY KEY AUTOINCREMENT, text VARCHAR(200));")
    if err != nil {
        fmt.Printf("error creating table "+tablename+": "+err.Error()+"\n") 
        return
    } else {
        fmt.Printf("successfully created table "+tablename+"!\n") 
    }
    var insertcount int = 128
    fmt.Printf("inserting %d random text rows ...\n", insertcount) 
    var counter int = 0
    insertloop:
    if counter < insertcount {
        counter++
        go func(count int) {
            if db.Exec("INSERT INTO "+tablename+"(text) VALUES(\""+getrandomtext()+"\");") !=nil {
                fmt.Printf(" -%d", count)
            } else {
                fmt.Printf(" +%d", count)
            }
        }(counter)
        goto insertloop
    }
    fmt.Printf("\nExecuted! Waiting some seconds...\n")
    time.Sleep(3000 * time.Millisecond)         
    fmt.Printf("\nRequesting...\n")
    ReadTable, err := db.Prepare("SELECT id, text FROM "+tablename+";")
    err = ReadTable.Query()
    if err != nil {
        fmt.Printf("failed to read '"+tablename+"' table, error: " + err.Error() + "\n")
        return
    } 
    Readloop:
    var RowId int
    var RowText string
    err = ReadTable.Scan(&RowId, &RowText)
    if err == nil {
        fmt.Printf("> %d | %s\n", RowId, RowText)
        ReadTable.Next() 
        goto Readloop
    }
    fmt.Printf("Sqlite3 test done! :)\n")
}
当我再次点击多任务GDB时,这会引起恐慌:

C:\Documents and Settings\JekabsR>multitaskingdb
successfully created table multiwrite!
inserting 128 random text rows ...

Executed! Waiting some seconds...
 +2 +3 +4 +5 +6 +7 +8 +9 +10panic: invalid memory address or nil pointer derefer
ence
fatal error: panic during malloc
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x41b60a]

runtime stack:
runtime.panic(panic: invalid memory address or nil pointer dereference
 +11 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -700x520a80, 0x673aaf)
        C:/Program Files/Go/src/pkg/runtime/panic.c:233 +0x2b
invalid spdelta 363589 -1
runtime: unexpected return pc for  -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -
82 -83 -84 -85 -86 -87 -88balance called from 0x200

goroutine 48 [syscall]:
runtime.cgocall(0x492817, 0x314476e8)
        C:/Program Files/Go/src/pkg/runtime/cgocall.c -89 -90 -91 -92 -93 -94 -9
5 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106:149 +0x10c fp=0x314476dc
code.google.com/p/go-sqlite/go1/sqlite3._Cfunc_sqlite3_exec(0x3d4258, 0x10f47480
, 0x0, 0x0, 0x0, ...)
        C:/DOCUME~1/JekabsR/LOCALS~1/Temp/go-build368528647/code.google.com/p/go
-sqlite/go1/sqlite3/_obj/_cgo_defun.c:456 +0x33 fp=0x314476e8
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).exec(0x10f2d6c0, 0x10f47480, 0x3
8 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29, 0x52f578)

        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:545 +0x4c fp=0x31447704
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).Exec(0x10f2d6c0, 0x10f47480,  +3
0 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +47 -48 -490x39, 0x0,
0x0, ...)
        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:231 +0xd2 fp=0x31447764
main.func┬Ę001( -50 -51 -52 -53 -54 -55 -56 +1 -107 -108 -109 -110 -111 -112 -11
3 -114 -115 -1160x2d)
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:52 +0xa2 fp=0x314477c4
runtime.goexit()
        C:/Program Files/Go/src/pkg/runtime/proc.c:1394 -117 -118 -119 -120 -121
 -122 -123 -124 -125 -126 -127 -128 +12 fp=0x314477c8
created by main.main
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:57 +0x417

goroutine 1 [sleep]:
time.Sleep(0xb2d05e00, 0x0)
        C:/Program Files/Go/src/pkg/runtime/time.goc:31 +0x3b
main.main()
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:61 +0x453

goroutine 3 [syscall]:
runtime.goexit()
        C:/Program Files/Go/src/pkg/runtime/proc.c:1394

goroutine 49 [syscall]:
code.google.com/p/go-sqlite/go1/sqlite3._Cfunc_sqlite3_exec(0x3d4258, 0x10f47500
, 0x0, 0x0, 0x0, ...)
        C:/DOCUME~1/JekabsR/LOCALS~1/Temp/go-build368528647/code.google.com/p/go
-sqlite/go1/sqlite3/_obj/_cgo_defun.c:456 +0x33
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).exec(0x10f2d6c0, 0x10f47500, 0x3
8, 0x52f578)
        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:545 +0x4c
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).Exec(0x10f2d6c0, 0x10f47500, 0x3
9, 0x0, 0x0, ...)
        C:/ProgramFiles/Go/src/pkg/code.google.com/p/go-sqlite/go1/sqlite3/sqlit
e3.go:231 +0xd2
main.func┬Ę001(0x2e)
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:52 +0xa2
created by main.main
        C:/Program Files/Go/src/pkg/development/multitaskingdb/multitaskingdb.go
:57 +0x417
fatal error: panic during malloc
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x41b60a]

runtime stack:
runtime.panic(0x520a80, 0x673aaf)
        C:/Program Files/Go/src/pkg/runtime/panic.c:233 +0x2b
invalid spdelta 364736 -1
runtime: unexpected return pc for sqlite3BtreeInsert called from 0x1500

问题出在哪里?

根据sqlite3包的文档,每个goroutine应该有一个连接,而不是多个goroutine共享一个连接

发件人:

并发性

单个连接实例及其所有派生实例 不能使用对象(准备好的语句、备份操作等) 同时来自多个goroutine,无需外部 同步。唯一的例外是Conn.Interrupt(),它可能是 从另一个goroutine调用以中止长时间运行的操作。它是 同时使用单独的连接实例是安全的,即使它们 正在访问同一数据库文件。例如:

// ERROR (without any extra synchronization)
c, _ := sqlite3.Open("sqlite.db")
go use(c)
go use(c)

// OK
c1, _ := sqlite3.Open("sqlite.db")
c2, _ := sqlite3.Open("sqlite.db")
go use(c1)
go use(c2)

随机评论:为什么不使用for循环来开始填充goroutines?@Volker for循环工作得很好,但我喜欢
goto
语句,并发现它很好地描述了循环。我没有注意到这一点。我在goroutine中插入了相同的初始化代码-
db,err:=sqlite3.Open(“文件:“+dbname+”?文件:locked.sqlite?cache=shared&mode=rwc”)
,将
db
重命名为
db2
,这个问题消失了。但现在它只插入128行中的大约8行,其他行则没有,看起来表被其他请求锁定了。您可以使用WaitGroup(或通道)代替计时器为了确保所有的goroutine都已完成,请在对数据库执行任何其他操作之前插入。我要说的是,从另一个goroutine锁定数据库应该请求对从另一个goroutine生成的数据库执行操作,只需阻塞等待锁定即可。
// ERROR (without any extra synchronization)
c, _ := sqlite3.Open("sqlite.db")
go use(c)
go use(c)

// OK
c1, _ := sqlite3.Open("sqlite.db")
c2, _ := sqlite3.Open("sqlite.db")
go use(c1)
go use(c2)