2013-02-08 1 views
4

J'écris une application web golang. L'application Web accède au système de fichiers (lecture et écriture) et à un fichier de base de données sqlite3.Synchronisation dans une application Web Go-lang

Question 1: Comment puis-je synchroniser l'accès au système de fichiers dans Go?

type DataObject struct { 
    data []byte 
} 

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

Question 2: Ai-je besoin de synchroniser l'accès aux fichiers de base de données 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 
} 

J'utilise le pilote gosqlite3 (http://code.google.com/p/gosqlite/).

Répondre

7

Pour les fichiers, cela dépend de votre application. Si vous avez seulement un goroutine qui écrit dans le fichier, vous ne devriez pas avoir besoin de le faire. Si plus d'un alors il dépend:

Si vous coordonnez entre différents processus (programmes) vous pouvez utiliser flock (et ce ne sera probablement pas amusant).

Si vous coordonnez plusieurs goroutines dans votre programme, vous pouvez utiliser mutexes ou vous pouvez voir si vous pouvez réorganiser le programme afin qu'une seule routine écrit dans le fichier et que les autres envoient des mises à jour via les canaux. Pour SQLite, je crois que le plus simple serait de garder une connexion sqlite ouverte et d'utiliser celle des goroutines; bien qu'il supporte plusieurs processus l'ayant ouvert en même temps et si votre système effectue plusieurs lectures simultanées qui pourraient être plus rapides (il utilise un verrou global pour l'écriture).

+1

+1 C'est mieux que ma réponse ;-) –

+1

Merci. Je suppose qu'une application Web dans Go est simultanée, et chaque demande est traitée dans une nouvelle routine go, donc je devrais synchroniser? – Kiril

+0

Oui, chaque requête http s'exécute dans son propre goroutine, vous devez donc les synchroniser ou utiliser un goroutine "helper" séparé (avec des canaux) pour gérer les éléments qui doivent être sérialisés. –

3

Question 1

Le package fournit "sync" Lock et rwlock pour synchroniser l'accès aux ressources de façon classique. Bien qu'il n'y ait rien de mal à cela, j'aime jouer avec les idiomes afin que je puisse faire quelque chose comme 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) 
    } 
} 

Alors si vous accédez uniquement le fichier par ce canal de funcs, l'accès sera synchronisé. C'est fiable, mais vous pourrez peut-être trouver quelque chose de plus efficace.

Question 2

Le pilote gosqlite3 est juste un Go obligatoire à libsqlite3, de sorte que le SQLite FAQ applique (et il semble que vous êtes en clair à ce sujet). Si vous souhaitez que ces deux éléments soient synchronisés entre eux, il vous suffit d'envelopper l'utilisation de SQLite dans le code de synchronisation d'accès au fichier.

+1

Votre réponse à la question n ° 2 est faux. Si vous ouvrez une fois la connexion à la base de données, vous pouvez la réutiliser simultanément. Si vous ne pouvez pas, votre implémentation de pilote "database/sql" a un bug: http://golang.org/src/pkg/database/sql/doc.txt?s=1209:1611#L31 – voidlogic

+0

Merci pour votre réponse . @voidlogic Donc, une fois que j'ai une connexion, je peux l'utiliser tout le temps, et avoir beaucoup de go-routines qui l'utilisent? – Kiril

+1

@Kiril: Oui, si votre application crée une seule instance de * sql.DB, vous pouvez l'utiliser à partir de plusieurs goroutines sans aucune synchronisation supplémentaire dans votre code. Si vous rencontrez un problème, assurez-vous de signaler le problème au responsable de l'implémentation du pilote SQL, car cela signifie que leur implémentation n'est pas compliment/a un bug. – voidlogic

2

1) Vous devez utiliser un mutex en lecture/écriture (dans la bibliothèque go std). code ressemblerait à quelque chose comme:

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) Comme vous l'avez pas posté la section « importation » de votre programme, je ne sais pas quel pilote SQLite que vous utilisez.

Si vous utilisez la base de données/sql pour ouvrir la connexion à la base de données, le pilote fournit un contrôle de simultanéité entre les goroutines.

+0

Salut, merci. J'utilise ce pilote: http://godoc.org/code.google.com/p/gosqlite/sqlite. Il est importé par: import "code.google.com/p/gosqlite/sqlite" – Kiril

0

Je sais que une vieille question, mais depuis que j'ai eu le même problème « de verrouillage db », et une transaction résolu pour moi, je pensais que je mentionne ici:

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