如何使用 channel

简介: 如何使用 Channel例子来自于Concurrency is not parallelismGoogle Search: A fake frameworkv1.0var ( Web = fakeSearch("web") Image = fakeSearch("image"...

如何使用 Channel

例子来自于Concurrency is not parallelism

Google Search: A fake framework

v1.0

var (
    Web = fakeSearch("web")
    Image = fakeSearch("image")
    Video = fakeSearch("video")
)

type Search func(query string) Result

func fakeSearch(kind string) Search {
        return func(query string) Result {
              time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
              return Result(fmt.Sprintf("%s result for %q\n", kind, query))
        }
}
func main() {
    rand.Seed(time.Now().UnixNano())
    start := time.Now()
    results := Google("golang")
    elapsed := time.Since(start)
    fmt.Println(results)
    fmt.Println(elapsed)
}

关键函数

func Google(query string) (results []Result) {
    results = append(results, Web(query))
    results = append(results, Image(query))
    results = append(results, Video(query))
    return
}

Google 2.0

每个 search, 独立并发.
No locks. No condition variables. No callbacks.

func Google(query string) (results []Result) {
    c := make(chan Result)
    go func() { c <- Web(query) } ()
    go func() { c <- Image(query) } ()
    go func() { c <- Video(query) } ()

    for i := 0; i < 3; i++ {
        result := <-c
        results = append(results, result)
    }
    return
}

Google 2.1

如果某个服务比较慢,怎么办?
No locks. No condition variables. No callbacks.

func Google(query string) (results []Result) {
    c := make(chan Result)
    go func() { c <- Web(query) } ()
    go func() { c <- Image(query) } ()
    go func() { c <- Video(query) } ()

    timeout := time.After(80 * time.Millisecond)
    for i := 0; i < 3; i++ {
        select {
        case result := <-c:
            results = append(results, result)
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
    return
}

Google 3.0 Avoid timeout

No locks. No condition variables. No callbacks.

func First(query string, replicas ...Search) Result {
    c := make(chan Result)
    searchReplica := func(i int) { c <- replicas[i](query) }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}
func Google(query string) (results []Result) {
   c := make(chan Result)
    go func() { c <- First(query, Web1, Web2) } ()
    go func() { c <- First(query, Image1, Image2) } ()
    go func() { c <- First(query, Video1, Video2) } ()
    timeout := time.After(80 * time.Millisecond)
    for i := 0; i < 3; i++ {
        select {
        case result := <-c:
            results = append(results, result)
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
    return
}

Google 3.1

上面的例子看起来挺完美,但是存在一个严重的内存泄漏,不知道你看出来没有.
First 中的 searchReplica调用,除了第一个会成功返回以外,其他都不会返回.因为堵塞在 c 上面,从而导致了内存泄漏.
改进也很简单

func First(query string, replicas ...Search) Result {
    c := make(chan Result,len(replicas)) //看似多分配了资源,但是很快就会收回
    searchReplica := func(i int) { c <- replicas[i](query) }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}

经过简单的替换,通过 Go 的并发模型,将一个慢的,顺序执行的,故障敏感的程序改造为了一个快速的,并发的,有冗余的,健壮的程序.

完整的 google 3.1

var (
    Web1 = fakeSearch("web")
    Web2 = fakeSearch("web")
    Image1 = fakeSearch("image")
    Image2 = fakeSearch("image")
    Video1 = fakeSearch("video")
    Video2 = fakeSearch("video")
)

type Search func(query string) Result

func fakeSearch(kind string) Search {
        return func(query string) Result {
              time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
              return Result(fmt.Sprintf("%s result for %q\n", kind, query))
        }
}
func main() {
    rand.Seed(time.Now().UnixNano())
    start := time.Now()
    results := Google("golang")
    elapsed := time.Since(start)
    fmt.Println(results)
    fmt.Println(elapsed)
}

func First(query string, replicas ...Search) Result {
    c := make(chan Result,len(replicas)) 
    searchReplica := func(i int) { c <- replicas[i](query) }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}
func Google(query string) (results []Result) {
   c := make(chan Result)
    go func() { c <- First(query, Web1, Web2) } ()
    go func() { c <- First(query, Image1, Image2) } ()
    go func() { c <- First(query, Video1, Video2) } ()
    timeout := time.After(80 * time.Millisecond)
    for i := 0; i < 3; i++ {
        select {
        case result := <-c:
            results = append(results, result)
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
    return
}
目录
相关文章
|
弹性计算 负载均衡 定位技术
阿里云服务器地域怎么选?地域选择四大因素考虑和建议
阿里云服务器地域怎么选?地域选择四大因素考虑和建议,阿里云服务器地域选择方法,如何选择速度更快、网络延迟更低的地域节点,地域指云服务器所在的地理位置区域,地域以城市划分,如北京、杭州、深圳及上海等,如何选择地域?建议根据用户所在地区就近选择地域,用户距离地域所在城市越近,网络延迟越低,速度越快。阿小云从速度延迟、备案限制、多产品内网互通、不同地域价格等四点因素来考虑地域的选择因素
|
3天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
14天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1303 5
|
13天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1329 87
|
2天前
|
弹性计算 安全 数据安全/隐私保护
2025年阿里云域名备案流程(新手图文详细流程)
本文图文详解阿里云账号注册、服务器租赁、域名购买及备案全流程,涵盖企业实名认证、信息模板创建、域名备案提交与管局审核等关键步骤,助您快速完成网站上线前的准备工作。
183 82
2025年阿里云域名备案流程(新手图文详细流程)