14.17. 使用 Channel 来并发读取对象

为了保护一个对象的并发修改,我们可以使用一个后台的协程来顺序执行一个匿名函数,而不是通过同步 互斥锁(Mutex) 进行锁定。

在下面的程序中,我们有一个 Person 类型,它包含了一个匿名函数类型的通道字段 chF。它在构造器方法 NewPerson 中初始化,用一个协程启动一个 backend() 方法。这个方法在一个无限 for 循环中执行所有被放到 chF 上的函数,有效的序列化他们,从而提供安全的并发访问。改变和获取 salary 可以通过一个放在 chF 上的匿名函数来实现,backend() 会顺序执行它们。注意如何在 Salary 方法中的闭合(匿名)函数中去包含 fChan 通道。

这是一个简化的例子,并且它不应该在这种情况下应用,但是它展示了如何在更复杂的情况下解决问题。

示例 14.19—conc_access.go:

package main

import (
    "fmt"

    "strconv"
)

type Person struct {
    Name string

    salary float64

    chF chan func()
}

func NewPerson(name string, salary float64) *Person {

    p := &Person{name, salary, make(chan func())}

    go p.backend()

    return p

}

func (p *Person) backend() {

    for f := range p.chF {

        f()

    }

}

// 设置 salary.

func (p *Person) SetSalary(sal float64) {

    p.chF <- func() { p.salary = sal }

}

// 取回 salary.

func (p *Person) Salary() float64 {

    fChan := make(chan float64)

    p.chF <- func() { fChan <- p.salary }

    return <-fChan

}

func (p *Person) String() string {

    return "Person - name is: " + p.Name + " - salary is: " +

    strconv.FormatFloat(p.Salary(), 'f', 2, 64)

}

func main() {

    bs := NewPerson("Smith Bill", 2500.5)

    fmt.Println(bs)

    bs.SetSalary(4000.25)

    fmt.Println("Salary changed:")

    fmt.Println(bs)

}

/* 输出结果:

Person - name is: Smith Bill - salary is: 2500.50

Salary changed:

Person - name is: Smith Bill - salary is: 4000.25 

*/

本文章首发在 LearnKu.com 网站上。
上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~