2013-02-08 61 views
4

我在写一个golang web应用程序。 Web应用程序访问文件系统(读写)和sqlite3数据库文件。Go-lang网络应用程序中的同步

问题1:如何在Go中同步文件系统访问?

type DataObject struct { 
    data []byte 
} 

func (*d DataObject) Write() { 
    // 
    // Synchronization ? 
    // 
    ioutil.WriteFile("file.name", d.data, 0644) 
    // 
    // Stop synchronization ? 
    // 
} 

问题2:我需要同步sqlite3的数据库文件的访问?

type SqlObject struct { 
    sqldata string 
} 

func (*s SqlObject) Store() error { 
    // 
    // Open the file, do I need some sort of synchronization? 
    // 
    con, err := sqlite.Open("database/datafile.db") 
    if err != nil { 
    return err 
    } 
    defer con.Close() 

    err = con.Exec("INSERT INTO data(sqldata) values(?)", s.sqldata) 
    if err != nil { 
    return err 
    } 
    return nil 
} 

我使用gosqlite3驱动程序(http://code.google.com/p/gosqlite/)。

回答

7

对于文件,它取决于您的应用程序。如果只有一个goroutine写入文件,则不需要。如果不止一个则取决于:

如果您正在协调不同的进程(程序),您可以使用flock(并且它可能不会很有趣)。

如果您在程序中协调多个goroutine,则可以使用mutexes,或者您可以查看是否可以重新组织程序,以便只有一个例程写入文件,其他例程通过通道发送更新。

对于SQLite我相信最简单的方法就是保持打开一个sqlite连接并使用来自各个goroutines的连接;尽管它支持多个进程一次打开,并且系统执行了许多可能更快的并发读取(它使用全局锁定写入)。

+1

+1这比我的回答好;-) – 2013-02-08 20:24:29

+1

谢谢。我假设Go中的一个Web应用程序是并发的,并且每个请求都在一个新的例程中处理,因此我应该同步? – Kiril 2013-02-09 12:50:45

+0

是的,每个http请求都在它自己的goroutine中运行,因此您必须在它们之间进行同步,或者使用单独的“helper”goroutine(带通道)来处理需要序列化的内容。 – 2013-02-21 18:04:26

3

问题1

"sync"包提供锁定和rwlock中用于以传统的方式同步到资源的访问。虽然没有什么不对的,我喜欢用成语玩弄所以我可能会做这样的事情this

package main 

import "fmt" 

func SyncFile(path string) chan<- func(string) { 
    ch := make(chan func(string)) 
    go func() { 
     for process := range ch { 
      process(path) 
     } 
    }() 
    return ch 
} 

func main() { 
    data := SyncFile("data.name") 
    data <- func(path string) { 
     fmt.Println(path) 
    } 
} 

然后,如果你只通过funcs中的这个通道访问该文件,访问将被同步。这是可靠的,但你可能能够找到更有效率的东西。

问题2

的gosqlite3司机只是一个围棋结合libsqlite3,所以SQLite FAQ应用(和它看起来像你在清澈的是这个)。如果您希望这两者都彼此同步,那么只需在文件访问同步代码中包装SQLite用法。

+1

你回答问题2是错的。如果您打开一次数据库连接,则可以同时重新使用它。如果你不能,那么你的“数据库/ sql”驱动程序实现有一个错误:http://golang.org/src/pkg/database/sql/doc.txt?s=1209:1611#L31 – voidlogic 2013-02-08 22:11:11

+0

谢谢你的回答。 @voidlogic所以,一旦我有连接,我可以在整个过程中使用它,并有许多正在使用它的例程? – Kiril 2013-02-09 12:49:08

+1

@Kiril:是的,如果您的应用程序创建* sql.DB的单个实例,那么您可以使用来自许多goroutine的实例,而无需在代码中进行任何额外的同步。如果遇到问题,请务必将问题报告给SQL驱动程序实施者,因为这意味着他们的实现不会恭维/有错误。 – voidlogic 2013-02-10 16:45:56

2

1)您应该使用读/写互斥锁(在标准库中)。 代码看起来是这样的:

import "sync" // http://golang.org/pkg/sync/ 
const (
    filename = "file.name" 
) 
var globalFileLock sync.RWMutex 

type DataObject struct { 
    data []byte 
} 

func (*d DataObject) Write() { 
    globalFileLock.Lock() 
    defer globalFileLock.Unlock() 
    ioutil.WriteFile(filename, d.data, 0644) 
} 

func (*d DataObject) Read() { 
    globalFileLock.RLock() 
    defer globalFileLock.RUnlock() 
    d.data = ioutil.ReadFile(filename) 
} 

2)当你还没有发布的从你的程序的“导入”部分,我不知道你使用的sqlite的驱动程序。

如果使用database/sql打开数据库连接,则驱动程序提供了goroutine之间的并发控制。

+0

嗨,谢谢。我使用这个驱动程序:http://godoc.org/code.google.com/p/gosqlite/sqlite。它是通过以下方式导入的:导入“code.google.com/p/gosqlite/sqlite” – Kiril 2013-02-09 12:47:43

0

我知道它的一个老问题,但因为我有同样的“DB锁”的问题,以及解决交易对我来说,我想我会在这里提到它:

db, err := sql.Open("sqlite3", db_path) 
if err != nil { 
    log.Printf("Cannot connect to database: %s\n", err) 
} 
defer db.Close() 
tx, _ := db.Begin() 
var value string 
err = tx.QueryRow("SELECT X FROM Y").Scan(&value) 
tx.Rollback() // or: tx.Commit()