1. 回调函数
回调函数是指一个函数作为参数传递给另一个函数,并在该函数内部被调用。在Golang中,可以使用函数类型作为参数来实现回调函数的功能。下面是一个简单的示例: ```go func callBackFunc(callback func()) { // 执行一些操作 callback() } func main() { callBackFunc(func() { fmt.Println("回调函数被执行") }) } ``` 上述代码中,我们定义了一个`callBackFunc`函数,它接受一个函数类型的参数`callback`,并在函数内部调用`callback`函数。在`main`函数中,我们通过匿名函数作为参数传递给`callBackFunc`函数,并输出了"回调函数被执行"。回调函数在并发编程中经常被用于处理任务完成后的通知或结果处理。然而,在多个并发任务中使用回调函数时,我们需要注意并发安全性问题。
2. 并发安全性
并发安全性是指多个并发任务对共享资源的访问不会产生冲突或导致数据不一致。在Golang中,我们可以使用锁来保护共享资源,以实现并发安全性。常见的锁机制有互斥锁(Mutex)和读写锁(RWMutex)。互斥锁用于保护临界区代码,确保在同一时刻只有一个goroutine可以访问共享资源。读写锁允许多个goroutine同时读取共享资源,但在写入时需要获取独占的锁。
3. Golang中的锁机制
Golang标准库提供了sync包,其中包括互斥锁(Mutex)和读写锁(RWMutex)。下面是使用互斥锁和回调函数的示例: ```go import ( "fmt" "sync" ) type Counter struct { count int mtx sync.Mutex } func (c *Counter) Increment(callback func()) { c.mtx.Lock() defer c.mtx.Unlock() c.count++ callback() } func main() { counter := Counter{} counter.Increment(func() { fmt.Println("回调函数被执行") }) } ``` 在上述代码中,我们定义了一个`Counter`结构体,内部包含一个计数器`count`和一个互斥锁`mtx`。`Increment`方法接受一个回调函数作为参数,并在临界区代码中对计数器进行加一操作,并通过回调函数通知任务完成。通过使用互斥锁,我们可以确保在`Increment`方法中的临界区代码执行期间,只有一个goroutine能够访问`count`字段。这样就避免了并发访问导致的数据不一致性问题。
4. 读写锁的应用
在某些情况下,我们希望允许多个goroutine同时读取共享资源,但在写入时需要获取独占锁。Golang中的读写锁(RWMutex)就能满足这种需求。 下面是一个使用读写锁和回调函数的示例: ```go import ( "fmt" "sync" ) type Database struct { data map[string]string rw sync.RWMutex } func (db *Database) Read(key string, callback func(value string)) { db.rw.RLock() defer db.rw.RUnlock() value := db.data[key] callback(value) } func (db *Database) Write(key, value string, callback func()) { db.rw.Lock() defer db.rw.Unlock() db.data[key] = value callback() } func main() { database := Database{ data: make(map[string]string), } database.Write("key", "value", func() { fmt.Println("写操作完成") }) database.Read("key", func(value string) { fmt.Println("读操作完成,值为", value) }) } ``` 在上述代码中,我们定义了一个`Database`结构体,内部包含一个数据映射类型`data`和一个读写锁`rw`。`Read`方法使用读锁来读取数据,并通过回调函数返回结果。`Write`方法使用写锁来更新数据,并在完成后执行回调函数。通过使用读写锁,我们可以实现多个goroutine同时读取数据的功能,并在写入时获取独占锁避免冲突。