063-Goroutine

欢迎来到新的章节—— Goroutine & Channel.

如果说 goroutine 是 Golang 中的倚天剑,那 channel 就是 Golang 里的屠龙大宝刀。早在第一章,我们就展示过 gotoutine 和 channel 的魅力了,如果你忘记了,可以再次回顾一遍《goroutine 和 chan》

我不会一遍又一遍的给你介绍 goroutine 的概念,一方面是因为你可能从未接触过协程,也不知道为什么有协程这个东西。难道仅仅是因为它比线程轻量吗?

其实要回答这个问题并不简单。只有在你充分了解并学习了异步 IO 编程的情况下,你才能感受到协程带来的便利性。没错,协程就是专为 IO 密集型服务器开发而生。

goroutine 可能和传统的协程概念并不完全一致,你可以认为它比协程更加灵活。协程往往是说运行在同一线程里的多条程序执行流。而 goroutine 是运行在多个线程上的多条程序执行流。

好了,为了不让你迷糊,上面这些概念你暂不用过多的去挖掘。相信我,慢慢你会掌握它的。

既然 goroutine 是 IO 密集型服务器的编程利器,那我们就从网络编程开始介绍它吧。

1. 并发服务器模型

学习过 steven 的 《unix 网络编程》,一定对网络编程不陌生。

如果你从未阅读或学习过这本书,强烈建议你去看看。Golang 并不是学习网络编程的最佳语言,只有 C 才是。从某种角度来说,使用 C 可以帮助你学习操作系统底层一些相关的原理和操作系统接口。如果你直接学习 Golang,这种过于高级的语言会帮你屏蔽掉太多的细节,其实对于你的学习并没有太多好处,充其量你也只是掌握了 Golang 的语法而已。
既然 C 语言这么牛逼,那为什么要用 Golang 而不用 C 来做服务器开发?在你充分掌握了网络编程技术细节后,使用 Golang 会让你如虎添翼,开发成本会大大降低。另外,使用 Golang 可以充分发挥机器性能。
有同学可能喜欢钻牛角尖,使用 C/C++ 难道就不能充分发挥机器性能吗?我只能说,这取决于你的编程水平。

假设我们还在使用 C/C++,要想解决并发问题,我们一般有下面几种解决方案:

  • 多进程阻塞 IO 模型(一客户一进程,容易实现,并发程度低)
  • 多线程阻塞 IO 模型(一客户一线程,容易实现,并发程度低)
  • 单/多线程 IO 多路复用 + 非阻塞 IO (开发难度最大,并发度最高)

想想就觉得很头疼是不是?好了,再来看看 Golang 是怎么做的:

  • 多协程阻塞 IO 模型(一客户一 goroutine,容易实现,并发程度高)

搞定。

简直爽爆了是不是?Golang 帮你搞定了太多的事情,屏蔽了太多的细节。你看,goroutine 既拥有多线程阻塞 IO 模型编写代码的便利性,也拥有 IO 多路复用 + 非阻塞 IO 的高并发特性,简直就是做服务器开发的同学们的福音。

2. echo server

echo server 简单吗?也许它很简单,也许一点也不简单。实现一个性能优异且没有 bug 的 echo server 更不简单。但是使用 golang,这就是一件轻而易举的事情。

首先来说说我们的 echo server 要支持什么功能:

  • 使用 tcp 协议
  • 客户端建立 tcp 长连接
  • 客户端流式发送数据,服务器将数据原封不动将数据发送回客户端。
  • 服务器能同时处理多个客户端的请求

下面是 Golang 版本的 echo server。不到 30 行,你就完成了一个高并发的 echo server。

package main

import (
    "io"
    "log"
    "net"
)

func main() {
    listener, err := net.Listen("tcp", ":8001")

    if err != nil {
        log.Fatal(err)
    }

    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
            continue
        }
        // 为客户端单独开一个协程
        go handleConn(conn)
    }
}

func handleConn(c net.Conn) {
    io.Copy(c, c)
    c.Close()
}

怎么测试呢?其实很简单,你的 Linux 系统一般会默认带一个工具叫 netcat,它既可以作为服务器也可以作为客户端。这里我们只需要使用它的客户端功能就行了。

$ nc localhost 8001 # 连接上你的 echo server
hello               # 输入 hello
hello               # 返回 hello
^D                  #  按下 CTRL D 退出
$

3. 总结

  • 掌握创建协程的语法

练习:写一个 Golang 版本的客户端,用来访问 echo server.

猜你喜欢

转载自blog.csdn.net/q1007729991/article/details/80721869
063
今日推荐