Golang Web应用程序中的同步

时间:2013-02-08 19:16:02

标签: web-applications concurrency sqlite synchronization go

我正在编写一个golang Web应用程序。 Web应用程序访问文件系统(读取和写入)和sqlite3数据库文件。

问题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/)。

4 个答案:

答案 0 :(得分:7)

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

如果您在不同的进程(程序)之间进行协调,则可以使用flock(这可能不会很有趣)。

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

对于SQLite,我认为最简单的方法是保持一个sqlite连接打开并使用来自各种goroutines的连接;虽然它确实支持多个进程同时打开它,如果你的系统执行许多可能更快的并发读取(它使用全局锁写入)。

答案 1 :(得分:4)

问题1

"sync"包提供了Lock和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)
    }
}

然后,如果您只通过此func通道访问该文件,则将同步访问。这是可靠的,但您可以找到更有效的东西。

问题2

gosqlite3驱动程序只是对libsqlite3的Go绑定,因此适用SQLite FAQ(看起来你已明白了)。如果您希望这两者彼此同步,那么只需将SQLite用法包装在文件访问同步代码中。

答案 2 :(得分:3)

1)您应该使用读/写互斥锁(在go std库中)。 代码看起来像:

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打开数据库连接,驱动程序会在goroutines之间提供并发控制。

答案 3 :(得分:-1)

我知道这是一个老问题,但由于我遇到了同样的“数据库锁定”问题,而且事务已经为我解决了,我想我会在这里提到它:

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()