2015-06-29 2 views
0

Я играю с this Библиотека SQLite для Go и при проведении стресс-тестирования столкнулась с некоторыми нечетными ошибками.Go SQlite Concurrency Issue

Я пытаюсь запустить этот код:

package main 

import "code.google.com/p/go-sqlite/go1/sqlite3" 
import "fmt" 
import "sync" 

func main() { 
    var wg sync.WaitGroup 
    wg.Add(100) 
    for i := 0; i < 100; i++ { 
     query(&wg, i) 
    } 
    wg.Wait() 
} 

func query(wg *sync.WaitGroup, id int) { 
    defer wg.Done() 
    c, _ := sqlite3.Open("sqlite.db") 
    for i := 0; i < 100; i++{ 
     args := sqlite3.NamedArgs{"$bval": "demo"} 
     sql := "SELECT rowid, * FROM x WHERE b = $bval" 
     row := make(sqlite3.RowMap) 
     for s, err := c.Query(sql, args); err == nil; err = s.Next() { 
       var rowid int64 
       s.Scan(&rowid, row)  // Assigns 1st column to rowid, the rest to row 
       fmt.Println(rowid, row) // Prints "1 map[a:1 b:demo c:<nil>]" 
     } 
    } 
    c.Close() 
    fmt.Println("Worker ", id, " is done") 
} 

По умолчанию, нет никаких проблем; Но когда я увеличиваю GOMAXPROCS более чем на 1, то программа вылетает в произвольных точках, что дает ошибку:

fatal error: unexpected signal during runtime execution 
[signal 0xb code=0x1 addr=0xc0000000d pc=0x4100b9] 

runtime stack: 
runtime.gothrow(0x5a1610, 0x2a) 
    /usr/lib/go/src/runtime/panic.go:503 +0x8e fp=0x7f4bd5ffa830 sp=0x7f4bd5ffa818 
runtime.sigpanic() 
    /usr/lib/go/src/runtime/sigpanic_unix.go:14 +0x5e fp=0x7f4bd5ffa880 sp=0x7f4bd5ffa830 

goroutine 1 [syscall, locked to thread]: 
runtime.cgocall_errno(0x408043, 0xc20808fcf8, 0x0) 
    /usr/lib/go/src/runtime/cgocall.go:130 +0xf5 fp=0xc20808fcd8 sp=0xc20808fcb0 
code.google.com/p/go-sqlite/go1/sqlite3._Cfunc_sqlite3_prepare_v2(0x7f4bc00023b8, 0xc2080483f0, 0xffffffff, 0xc20808fd30, 0xc20808fd28, 0x0) 
    /home/eumen/Programming/gocode/src/code.google.com/p/go-sqlite/go1/sqlite3/:534 +0x43 fp=0xc20808fcf8 sp=0xc20808fcd8 
code.google.com/p/go-sqlite/go1/sqlite3.newStmt(0xc2080482d0, 0x599e90, 0x26, 0xc20804b8c8, 0x0, 0x0) 
    /home/eumen/Programming/gocode/src/code.google.com/p/go-sqlite/go1/sqlite3/sqlite3.go:583 +0xe4 fp=0xc20808fdb0 sp=0xc20808fcf8 
code.google.com/p/go-sqlite/go1/sqlite3.(*Conn).Query(0xc2080482d0, 0x599e90, 0x26, 0xc20808fee0, 0x1, 0x1, 0xc20807a000, 0x0, 0x0) 
    /home/eumen/Programming/gocode/src/code.google.com/p/go-sqlite/go1/sqlite3/sqlite3.go:276 +0xc3 fp=0xc20808fe00 sp=0xc20808fdb0 
main.query(0xc208022020, 0x16) 
    /home/eumen/Programming/Go/practice/sqlite-sync.go:26 +0x261 fp=0xc20808ff70 sp=0xc20808fe00 
main.main() 
    /home/eumen/Programming/Go/practice/sqlite-sync.go:11 +0x66 fp=0xc20808ff98 sp=0xc20808ff70 
runtime.main() 
    /usr/lib/go/src/runtime/proc.go:63 +0xf3 fp=0xc20808ffe0 sp=0xc20808ff98 
runtime.goexit() 
    /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc20808ffe8 sp=0xc20808ffe0 

goroutine 2 [force gc (idle)]: 
runtime.gopark(0x496870, 0x831d30, 0x583f70, 0xf) 
    /usr/lib/go/src/runtime/proc.go:130 +0x105 fp=0xc20801e798 sp=0xc20801e768 
runtime.goparkunlock(0x831d30, 0x583f70, 0xf) 
    /usr/lib/go/src/runtime/proc.go:136 +0x48 fp=0xc20801e7c0 sp=0xc20801e798 
runtime.forcegchelper() 
    /usr/lib/go/src/runtime/proc.go:99 +0xce fp=0xc20801e7e0 sp=0xc20801e7c0 
runtime.goexit() 
    /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc20801e7e8 sp=0xc20801e7e0 
created by runtime.init·4 
    /usr/lib/go/src/runtime/proc.go:87 +0x25 

goroutine 3 [GC sweep wait]: 
runtime.gopark(0x496870, 0x838ff8, 0x580b50, 0xd) 
    /usr/lib/go/src/runtime/proc.go:130 +0x105 fp=0xc208021f98 sp=0xc208021f68 
runtime.goparkunlock(0x838ff8, 0x580b50, 0xd) 
    /usr/lib/go/src/runtime/proc.go:136 +0x48 fp=0xc208021fc0 sp=0xc208021f98 
runtime.bgsweep() 
    /usr/lib/go/src/runtime/mgc0.go:98 +0xbc fp=0xc208021fe0 sp=0xc208021fc0 
runtime.goexit() 
    /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc208021fe8 sp=0xc208021fe0 
created by gc 
    /usr/lib/go/src/runtime/mgc0.c:1386 

goroutine 4 [finalizer wait]: 
runtime.gopark(0x496870, 0x838ff0, 0x583ad0, 0xe) 
    /usr/lib/go/src/runtime/proc.go:130 +0x105 fp=0xc20801d730 sp=0xc20801d700 
runtime.goparkunlock(0x838ff0, 0x583ad0, 0xe) 
    /usr/lib/go/src/runtime/proc.go:136 +0x48 fp=0xc20801d758 sp=0xc20801d730 
runtime.runfinq() 
    /usr/lib/go/src/runtime/malloc.go:727 +0xba fp=0xc20801d7e0 sp=0xc20801d758 
runtime.goexit() 
    /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc20801d7e8 sp=0xc20801d7e0 
created by runtime.createfing 
    /usr/lib/go/src/runtime/malloc.go:707 +0x5e 

goroutine 17 [syscall, locked to thread]: 
runtime.goexit() 
    /usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc208032fe8 sp=0xc208032fe0 
signal: aborted (core dumped) 

Эта ошибка возникает только тогда, когда я увеличиваю GOMAXPROCS, а также происходит, если я использую go query(&wg, i). Как ни странно, ошибки также не возникают, если цикл не используется, или если i установлен на достаточно малое число. Кто-нибудь сможет пролить свет на то, что здесь происходит?

ответ

0

Библиотека вы используете не поддерживает параллелизм согласно https://code.google.com/p/go-sqlite/source/browse/go1/sqlite3/doc.go#29 -

Concurrency

A single connection instance and all of its derived objects (prepared statements, backup operations, etc.) may NOT be used concurrently from multiple goroutines without external synchronization. The only exception is Conn.Interrupt(), which may be called from another goroutine to abort a long-running operation. It is safe to use separate connection instances concurrently, even if they are accessing the same database file.

Как sqlite3 является база данных на основе файлов, водитель должен управлять одновременный доступ из нескольких потоков.

https://github.com/mattn/go-sqlite3 библиотека should support thread-safe операция, при условии, что ваш sqlite3 был скомпилирован для этого.

+1

У меня создалось впечатление, что до тех пор, пока я создавал новый Open при каждом вызове функции, он не нарушал бы требования к параллелизму библиотек, но я думаю, что когда работает многопоточность Go Go, это не так. Спасибо за информацию. –

+0

Вы часто лучше создаете единый '* sql.DB' - будь то глобальный или явно переданный вашим обработчикам/функциям из' main() 'и повторно используя это вместо' Open (...); defer Закрыть() 'в каждой функции. Меньше накладных расходов. – elithrar

+1

Да, это то, что я делаю в самом приложении, которое я пишу в данный момент. В этом вопросе я просто играл, чтобы узнать, будет ли SQLite задерживаться при параллелизме. После повторения подобных тестов с библиотекой, которую вы рекомендовали, похоже, что это так, и тоже неплохо. –