15

四段代码入门Go协程以及channel!

 4 years ago
source link: https://www.tuicool.com/articles/ENJFnm7
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

写一个简单的程序,使得一个协程用来向channel中写如数据,一个用来读取数据。

import (
    "fmt"
    "strconv"
    "testing"
)
/**
在这个示例中,我们有
  - 一个message作为channel
  - 一个协程用来发送消息
  - 主协程用来接收消息
*/
func Test_message(t *testing.T)  {
    /**
    声明一个长度为 1 的channel
    */
    messages := make(chan string)

    /**
    该协程负责向channel发送数据,共发送五次
    */
    go func() {
        for i := 0; i < 5; i++ {
            messages <- "Hello, 这是第 " + strconv.Itoa(i) + " 次传递消息"
        }
    }()

    /**
    读取channel中的数据,这是个阻塞的操作
    */
    for i := 0; i < 5; i++ {
        fmt.Println(<- messages)
    }
}

代码样例

然后下面是三段代码,大家看之前可以小思考下运行结果,最好自己动手测试下。

假如向channel中写入数据时,设置1秒钟的延迟,那么读取channel数据的协程会阻塞吗?

import (
    "fmt"
    "strconv"
    "testing"
    "time"
)

/**
在这个示例中,我们的副协程在向channel中写入数据的时候,有一秒的延迟

然后我们发现控制台断断续续的打印出了内容

说明我们从channel中读取消息是个阻塞的行为
 */
func Test_message1(t *testing.T)  {
    /**
    声明一个长度为 1 的channel
     */
    messages := make(chan string)

    /**
    该协程每隔一秒向channel发送一个数据
     */
    go func() {
        for i := 0; i < 5; i++ {
            time.Sleep(time.Second * 1)
            messages <- "Hello, 这是第 " + strconv.Itoa(i) + " 次传递消息"
        }
    }()

    /**
    读取channel中的数据,这是个阻塞的操作
     */
    for i := 0; i < 5; i++ {
        fmt.Println(<- messages)
    }
}

当然是阻塞的,写协程阻塞了,读协程只能干等着啊,这个问题好像有点(๑•ᴗ•๑)

如果给读协程设置一秒延迟,那么写协程会阻塞吗?

import (
    "fmt"
    "strconv"
    "testing"
    "time"
)

/**
在这个示例中,我们向channel中读取数据时,设置了一秒的延迟

然后我们发现控制台断断续续的打印出了内容

说明我们向channel中写入消息也是是个阻塞的行为
它受到channel容量的限制,如果channel容量满了,写操作就会阻塞协程
*/
func Test_message2(t *testing.T)  {
    /**
    声明一个长度为一的channel
    */
    messages := make(chan int)

    /**
    该协程每隔一秒向channel发送一个数据
    */
    go func() {
        for i := 0; i < 5; i++ {
            messages <- i
            fmt.Println("Hello, 这是第 " + strconv.Itoa(i) + " 次传递消息")
        }
    }()

    /**
    读取channel中的数据,这是个阻塞的操作
    */
    for i := 0; i < 5; i++ {
        <- messages
        time.Sleep(time.Second * 1)
    }
}

答案是会的,因为channel的容量是有限的,没有消费者的话,生产者是不能继续生产的。

如何给channel设置一个5的容积,那么下面程序的运行结果会是怎么样的?

import (
    "fmt"
    "strconv"
    "testing"
    "time"
)

/**
在这个示例中,我们创建了一个有缓存channel

大家可以自行执行以下,可以看到前面6次打印非常快,后面三次则是断断续续的

这就是有缓冲的channel,即使没有消费者,我们依旧可以向channel中写入数据,
直到容量达到上限
*/
func Test_message3(t *testing.T)  {
    /**
    声明一个容量为5的channel
    */
    messages := make(chan int, 5)

    /**
    该协程持续的尝试向channel中发送一个数据
    */
    go func() {
        for i := 0; i < 10; i++ {
            messages <- i
            fmt.Println("Hello, 这是第 " + strconv.Itoa(i) + " 次传递消息")
        }
    }()

    /**
    每隔一秒读取一次channel中的数据,这是造成channel内元素逐渐累积
    */
    for i := 0; i < 5; i++ {
        <- messages
        time.Sleep(time.Second * 1)
    }
}

答案是前面6次打印非常快,后面三次则是断断续续的

怎么样,是不是对协程和channel有了基本的认识了

https://github.com/fish-bugs/...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK