golang高并发的思想与实践

引言

Go语言的高并发是go语言引以为傲的一点,也是其它语言爱好者感觉到好奇并想要有一定了解的方面。

首先,Go语言在语言设计上就添加了关于开启并发的关键字“go”,使得在程序员编程方面实现并发特别简单

其次,有了Channels和goroutines,goroutines定义为协程

1协程本质上是一种用户态线程,不需要操作系统来进行抢占式调度,并且在真正的实现中寄存于线程中,因此系统的开销非常小,可以有小的提高线程任务的并发性,避免多线程多的缺点

2优势巨大,轻量级,可以轻松创建上百万个而不会导致系统资源衰竭,而线程和进程最多也不能超过一万个

3语言标准库提供的所有系统的调用操作(包括同步IO操作),可以让CPU给其它goroutine,让轻量级线程的切换管理不依赖于系统的线程也不依赖与线程和进程,也不依赖于CPU的核心量

Channels

当软件的输出取决于事件发生的时间和顺序时,因为我们无法控制,bug 就会出现。因为我们无法准确控制每个 goroutine 写入结果 map 的时间,两个 goroutines 同一时间写入时程序将非常脆弱。Channels是通道,在协程之间促进信息流通,它是一个数据结构,可以同时接受和发送值,可以协调我们的goroutines来解决数据竞争

  • goroutines 是 Go 的基本并发单元,它让我们可以同时检查多个网站。

  • anonymous functions(匿名函数),我们用它来启动每个检查网站的并发进程。

  • channels,用来组织和控制不同进程之间的交流,使我们能够避免 race condition(竞争条件) 的问题。

  • the race detector(竞争探测器) 帮助我们调试并发代码的问题。

现在,从新一点系统的了解go语言中的高并发

go语言中协程的启动特别简单,仅仅在需要并发的函数前面加上关键字 go 即可

package concurrency

type WebsiteChecker func(string) bool

func CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool {
    results := make(map[string]bool)

    for _, url := range urls {
        go func() {
            results[url] = wc(url)
        }()
    }

    return results
}

结果是这个程序并没有达到比较url的效果,没有任何返回值,原因是WebsiteChecker函数对于goroutines来说太快了

为了使得goroutines能够跟上脚步,我们可以使用sleep让它们完成工作

package concurrency

import "time"

type WebsiteChecker func(string) bool

func CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool {
    results := make(map[string]bool)

    for _, url := range urls {
        go func() {
            results[url] = wc(url)
        }()
    }

    time.Sleep(2 * time.Second)

    return results
}

给了两秒钟的时间让goroutines可以完成它们的工作,但等待协程进行的这个方法并不保险,当我们进行多次测试,两个goroutine完全同时写入results map就能导致fatal error

这就是race condition(竞争条件),当软件的输出取决于事件发生的时间和顺序是,我们没有办法控制,两个goroutines同时写入,使得程序特别脆弱。

但是,go语言就为我们设计了一个方式来解决问题,Channels

package concurrency

type WebsiteChecker func(string) bool
type result struct {
    string
    bool
}

func CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool {
    results := make(map[string]bool)
    resultChannel := make(chan result)

    for _, url := range urls {
        go func(u string) {
            resultChannel <- result{u, wc(u)}
        }(url)
    }

    for i := 0; i < len(urls); i++ {
        result := <-resultChannel
        results[result.string] = result.bool
    }

    return results
}

除了 results map 之外,我们现在还有一个 resultChannel 的变量,同样使用 make 方法创建。chan result 是 channel 类型的 —— result 的 channel。新类型的 result 是将 WebsiteChecker 的返回值与正在检查的 url 相关联 —— 它是一个 stringbool 的结构。因为我们不需要任何一个要命名的值,它们中的每一个在结构中都是匿名的;这在很难知道用什么命名值的时候可能很有用。

现在,当我们迭代 urls 时,不是直接写入 map,而是使用 send statement 将每个调用 wcresult 结构体发送到 resultChannel。这使用 <- 操作符,channel 放在左边,值放在右边:

下一个 for 循环为每个 url 迭代一次。 我们在内部使用 receive expression,它将从通道接收到的值分配给变量。这也使用 <- 操作符,但现在两个操作数颠倒过来:现在 channel 在右边,我们指定的变量在左边:

然后我们使用接收到的 result 更新 map。

通过将结果发送到通道,我们可以控制每次写入 results map 的时间,确保每次写入一个结果。虽然 wc 的每个调用都发送给结果通道,但是它们在其自己的进程内并行发生,因为我们将结果通道中的值与接收表达式一起逐个处理一个结果。

我们已经将想要加快速度的那部分代码并行化,同时确保不能并发的部分仍然是线性处理。我们使用 channel 在多个进程间通信。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
golang中,高并发项目实战可以通过使用goroutines和channels来实现。其中,goroutines是轻量级的线程,可以并发执行多个任务,而channels则用于goroutines之间的通信。 一个常见的高并发项目实战是使用golang开发网络爬虫。网络爬虫是一种通过自动化程序浏览互联网,并从网页中提取数据的技术。在golang中,可以使用第三方的爬虫框架来简化开发过程,如引用所提到的爬虫框架。 在这个项目中,可以将爬虫框架的处理模块分为下载器、分析器和条目处理器。下载器负责从指定的URL下载网页内容,分析器用于解析网页并提取需要的数据,而条目处理器则对提取的数据进行处理。此外,还需要一个调度和协调这些处理模块运行的控制模块来确保它们按照预期的方式运行。 为了实现高并发,可以将每个任务(即要爬取的URL)分配给一个goroutine来执行。可以使用goroutine和channel的组合来实现任务的并发执行和结果的收集。引用中给出了一个示例函数CheckWebsites,该函数接收一个WebsiteChecker函数和一个URL列表,并返回一个映射,其中URL与检查结果对应。 在该示例函数中,使用了一个resultChannel来收集每个URL的检查结果。通过使用goroutine,在遍历URL列表时,可以将每个URL的检查结果发送到resultChannel中。然后,通过在循环中使用<-resultChannel来接收结果,并将结果存储在一个map中。 通过这种方式,可以实现高并发的URL检查,并在所有检查完成后返回结果。 总之,golang高并发项目实战可以通过使用goroutines和channels来实现并发执行任务和结果的收集。网络爬虫是一个常见的高并发项目实战示例,通过使用爬虫框架和适当的并发控制,可以实现高效的网页数据提取。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [golang GRPC 高并发实战1:基础环境搭建](https://blog.csdn.net/xatop/article/details/123326480)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [golang爬虫框架,golang高并发实战](https://download.csdn.net/download/weixin_44772356/87273641)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [golang高并发思想实践](https://blog.csdn.net/m0_58181788/article/details/123938547)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值