在Go语言的Web应用程序中的同步

huangapple go评论89阅读模式
英文:

Synchronization in a Go-lang webapplication

问题

我正在编写一个使用golang的web应用程序。这个web应用程序访问文件系统(读写)和一个sqlite3数据库文件。

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

type DataObject struct {
  data []byte
}

func (*d DataObject) Write() {
   //
   // 同步?
   //
   ioutil.WriteFile("file.name", d.data, 0644)
   //
   // 停止同步?
   //
}

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

type SqlObject struct {
  sqldata string
}

func (*s SqlObject) Store() error {
  //
  // 打开文件,我需要某种形式的同步吗?
  //
  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/)。

英文:

I'm writing a golang web application. The web application accesses the file system (reading and writing) and an sqlite3 database file.

Question 1: How can I synchronize file system access in Go?

type DataObject struct {
  data []byte
}

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

Question 2: Do I need to synchronize sqlite3 database file access?

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
}

I'm using the gosqlite3 driver (http://code.google.com/p/gosqlite/).

答案1

得分: 7

对于文件,这取决于你的应用程序。如果只有一个goroutine写入文件,你不需要。如果有多个goroutine写入文件,则取决于以下情况:

如果你在不同的进程(程序)之间进行协调,你可以使用flock(可能不太容易)。

如果你在程序中协调多个goroutine,你可以使用mutexes,或者你可以尝试重新组织程序,使得只有一个例程写入文件,其他例程通过通道发送更新。

对于SQLite,我认为最简单的方法是保持一个sqlite连接打开,并从各个goroutine中使用它;尽管它支持多个进程同时打开,如果你的系统进行许多并发读取,那可能会更快(它使用全局锁进行写入)。

英文:

For files it depends on your application. If you only have one goroutine writing to the file, you shouldn't need to. If more than one then it depends:

If you are coordinating between different processes (programs) you can use flock (and it probably won't be fun).

If you are coordinating multiple goroutines in your program you can use mutexes or you can see if you can re-organize the program so just one routine writes to the file and the others send updates via channels.

For SQLite I believe the easiest way would be to just keep one sqlite connection open and use that from the various goroutines; though it does support multiple processes having it open at once and if your system does many concurrent reads that might be faster (it uses a global lock for writing).

答案2

得分: 4

问题1

"sync"包提供了Lock和RWLock,用于以传统方式同步访问资源。虽然这没有什么问题,但我喜欢尝试不同的习语,所以我可能会做类似于这样的事情:

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

然后,如果你只通过这个函数通道访问文件,访问将会同步。这是可靠的,但你可能能找到更高效的方法。

问题2

gosqlite3驱动程序只是libsqlite3的Go绑定,因此适用SQLite FAQ(看起来你在这方面是安全的)。如果你希望这两者彼此同步,只需将SQLite使用包装在文件访问同步代码中即可。

英文:

Question 1

The "sync" package provides Lock and RWLock for synchronizing access to resources in the conventional way. While there's nothing wrong with that, I like playing around with idioms so I might do something like 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)
	}
}

Then if you only access the file through this channel of funcs, access will be synchronized. This is reliable, but you may be able to find something more efficient.

Question 2

The gosqlite3 driver is just a Go binding to libsqlite3, so the SQLite FAQ applies (and it looks like you're in the clear on this). If you want both of these to be synchronized with each other, then just wrap the SQLite usage inside the file access synchronization code.

答案3

得分: 3

你应该使用一个读写互斥锁(在go标准库中)。
代码应该如下所示:

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

由于您没有发布程序的“import”部分,我不知道您正在使用哪个sqlite驱动程序。
如果您正在使用database/sql来打开数据库连接,驱动程序提供了协程之间的并发控制。

英文:
  1. You should use a read/write mutex (in the go std library).
    Code would look something like:

    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. As you haven't posted the 'import' section from your program, I don't know which sqlite driver you're using.

If you are using database/sql to open the database connection, the driver provides concurrency control between goroutines.

答案4

得分: -1

我知道这是一个旧问题,但由于我遇到了相同的“db lock”问题,并且一个事务解决了我的问题,所以我想在这里提一下:

db, err := sql.Open("sqlite3", db_path)
if err != nil {
log.Printf("无法连接到数据库:%s\n", err )
}
defer db.Close()
tx, _ := db.Begin()
var value string
err = tx.QueryRow("SELECT X FROM Y").Scan(&value)
tx.Rollback() // 或者:tx.Commit()

英文:

I know its an old question but since I had the same "db lock" problem, and a transaction resolved it for me, I thought I'd mention it here:

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

huangapple
  • 本文由 发表于 2013年2月9日 03:16:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/14779769.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定