在Go语言中实现对同一个文件的写抢占,意味着你需要确保在任何给定时间点,只有一个goroutine(或者进程)能够写入文件。这通常通过文件锁来实现。下面是一个使用之前提到的gofrs/flock
库来实现文件写操作抢占的示例。
这个示例将演示如何在多个goroutine中对同一文件进行写操作,但确保每次只有一个goroutine能写入。
首先,确保你已经安装了gofrs/flock
库:
go get github.com/gofrs/flock
然后,你可以创建一个程序如下:
package main
import (
"fmt"
"github.com/gofrs/flock"
"os"
"strconv"
"sync"
"time"
)
// writeFile尝试获取文件锁并写入数据
func writeFile(id int, wg *sync.WaitGroup, lock *flock.Flock) {
defer wg.Done()
// 尝试获取锁
locked, err := lock.TryLock()
if err != nil {
fmt.Printf("Goroutine %d: 错误 - %s\n", id, err)
return
}
if !locked {
fmt.Printf("Goroutine %d: 未能获取锁,跳过\n", id)
return
}
// 拿到锁后写入文件
fmt.Printf("Goroutine %d: 获取到了锁\n", id)
file, err := os.OpenFile(lock.Path(), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Printf("Goroutine %d: 打开文件错误 - %s\n", id, err)
return
}
defer file.Close()
_, err = file.WriteString("Goroutine " + strconv.Itoa(id) + " was here.\n")
if err != nil {
fmt.Printf("Goroutine %d: 写文件错误 - %s\n", id, err)
return
}
// 完成后解锁
if err := lock.Unlock(); err != nil {
fmt.Printf("Goroutine %d: 解锁失败 - %s\n", id, err)
return
}
fmt.Printf("Goroutine %d: 写入并解锁成功\n", id)
}
func main() {
var wg sync.WaitGroup
lock := flock.New("test.lock")
for i := 1; i <= 5; i++ {
wg.Add(1)
go writeFile(i, &wg, lock)
// 为了更好地观察竞争情况,这里我们在启动goroutine之间故意加入短暂的睡眠
time.Sleep(100 * time.Millisecond)
}
wg.Wait()
fmt.Println("所有goroutine完成")
}
这个程序创建了5个goroutine,每个goroutine都尝试对同一个文件加锁,并在成功获取锁之后写入一些信息。通过gofrs/flock
库,我们可以确保同一时间只有一个goroutine能够写入文件,从而避免了写入操作的竞争条件。
请注意,执行这段代码时,你可能会看到并不是所有goroutine都能成功写入文件。这是因为如果一个goroutine已经持有了锁,其他尝试获取锁的goroutine将不能获取锁,因此会跳过写入操作。这种机制确保了文件写入的互斥性。