当前位置: 首页 > news >正文

怎么在网站底部做备案号哈尔滨优化网站公司

怎么在网站底部做备案号,哈尔滨优化网站公司,创建小型网站的步骤,上海做兼职哪个网站靠谱吗在本教程中,我们将讨论Channel以及 Goroutines 如何使用Channel进行通信。 什么是Channel Channel可以被认为是 Goroutine 用来进行通信的管道。与水在管道中从一端流向另一端的方式类似,可以使用Channel从一端发送数据并从另一端接收数据。 声明Chan…

在本教程中,我们将讨论Channel以及 Goroutines 如何使用Channel进行通信。

什么是Channel

Channel可以被认为是 Goroutine 用来进行通信的管道。与水在管道中从一端流向另一端的方式类似,可以使用Channel从一端发送数据并从另一端接收数据。

声明Channel

每个Channel都有一个与其关联的类型。该类型是Channel允许传输的数据类型。不允许使用该Channel传输其他类型。

chan T是一个Channel类型是T

Channel的零值为nilnil的Channel没有任何用处,因此必须使用make类似于map和slices来定义Channel。

让我们编写一些声明Channel的代码。

package mainimport "fmt"func main() {  var a chan intif a == nil {fmt.Println("channel a is nil, going to define it")a = make(chan int)fmt.Printf("Type of a is %T", a)}
}

Run program in playground

第 1 行中声明的Channel,此时的Channel是nil。因此,会执行 if 条件内的语句并定义Channel。该程序将输出,

channel a is nil, going to define it  
Type of a is chan int  

与往常一样,简写声明也是定义Channel的有效且简洁的方式。

a := make(chan int)  

上面的代码行还定义了一个 int Channel变量a

从Channel发送和接收

下面给出了从Channel发送和接收数据的语法:

data := <- a // read from channel a  
a <- data // write to channel a  

箭头相对于Channel的方向指定是发送还是接收数据。

在第一行中,箭头指向外部a,因此我们从Channel读取a并将值存储到变量data

在第二行中,箭头指向a,因此我们正在向写入通道写入a

默认情况下发送和接收是阻塞的

默认情况下,向Channel发送和接收是阻塞的。这是什么意思?当数据发送到Channel时,控制会在发送语句中被阻塞,直到其他 Goroutine 从该Channel读取数据。类似地,当从Channel读取数据时,读取会被阻塞,直到某个 Goroutine 将数据写入该Channel。

Channel的这一属性有助于 Goroutines 有效地进行通信,而无需使用其他编程语言中很常见的显式锁或条件变量。

如果现在这没有意义也没关系。接下来的部分将更清楚地说明默认情况下Channel是如何阻塞的。

Channel示例程序

让我们编写一个程序来了解 Goroutine 如何使用Channel进行通信。

让我引用上一篇教程中的程序。

package mainimport (  "fmt""time"
)func hello() {  fmt.Println("Hello world goroutine")
}
func main() {  go hello()time.Sleep(1 * time.Second)fmt.Println("main function")
}

Run program in playground

这是上一个教程中的程序。我们在这里使用 sleep 来让主 Goroutine 等待 hello Goroutine 完成。

我们将使用Channel重写上面的程序。

package mainimport (  "fmt"
)func hello(done chan bool) {  fmt.Println("Hello world goroutine")done <- true
}
func main() {  done := make(chan bool)go hello(done)<-donefmt.Println("main function")
}

Run program in playground

在上面的程序中,我们在第 1 行创建了一个布尔Channel。 并将其作为参数传递给helloGoroutine。在14行号中。 我们正在从doneChannel接收数据。这行代码是阻塞的,这意味着在某个 Goroutine 将数据写入Channel之前done,控件不会移动到下一行代码。因此,这消除了原始程序中存在的用于防止主 Goroutine 退出的需要time.Sleep

该代码行<-done从完成的Channel接收数据,但不使用该数据或将该数据存储在任何变量中。这是完全合法的。

现在我们的mainGoroutine 被阻塞,等待完成Channel上的数据。Goroutinehello接收此Channel作为参数,打印Hello world goroutine然后写入done。当此写入完成时,主 Goroutine 会从 did Channel接收数据,解除阻塞,然后打印主函数。

该程序输出

Hello world goroutine  
main function  

让我们通过在 Goroutine 中引入 sleep 来修改此程序,hello以更好地理解这种阻塞概念。

package mainimport (  "fmt""time"
)func hello(done chan bool) {  fmt.Println("hello go routine is going to sleep")time.Sleep(4 * time.Second)fmt.Println("hello go routine awake and going to write to done")done <- true
}
func main() {  done := make(chan bool)fmt.Println("Main going to call hello go goroutine")go hello(done)<-donefmt.Println("Main received data")
}

Run program in playground

在上面的程序中,我们在第 10 行的函数中引入了 4 秒的睡眠。.

该程序将首先打印Main going to call hello go goroutine. 然后 hello Goroutine 将启动并打印hello go routine is going to sleep。打印完此信息后,helloGoroutine 将休眠 4 秒,在此期间,mainGoroutine 将被阻塞,因为它正在等待第 18 行完成Channel的数据<-donehello go routine awake and going to write to done后将打印,然后是Main received data.

Main going to call hello go goroutine
hello go routine is going to sleep
hello go routine awake and going to write to done
Main received data

Channel的另一个例子

让我们再编写一个程序来更好地理解Channel。该程序将打印一个数字的各个数字的平方和和立方之和。

例如,如果输入为 123,则该程序将计算输出为

正方形 = (1 * 1) + (2 * 2) + (3 * 3)
立方体 = (1 * 1 * 1) + (2 * 2 * 2) + (3 * 3 * 3)
输出 = 正方形 + 立方体 = 50

我们将构建该程序,使得平方在单独的 Goroutine 中计算,立方体在另一个 Goroutine 中计算,最终求和发生在主 Goroutine 中。

package mainimport (  "fmt"
)func calcSquares(number int, squareop chan int) {  sum := 0for number != 0 {digit := number % 10sum += digit * digitnumber /= 10}squareop <- sum
}func calcCubes(number int, cubeop chan int) {  sum := 0 for number != 0 {digit := number % 10sum += digit * digit * digitnumber /= 10}cubeop <- sum
} func main() {  number := 589sqrch := make(chan int)cubech := make(chan int)go calcSquares(number, sqrch)go calcCubes(number, cubech)squares, cubes := <-sqrch, <-cubechfmt.Println("Final output", squares + cubes)
}

Run program in playground

第 7行中的函数calcSquares。 计算该数字各个数字的平方和并将其发送到squareop。同样,第 17 行中的calcCubes函数。计算数字各个数字的立方和并将其发送到cubeop

这两个函数在第31行 和 32行中作为单独的 Goroutine 运行。每个Channel都传递一个要写入的参数作为参数。主 Goroutine 在第 33 行等待来自这两个Channel的数据。 一旦从两个Channel接收到数据,它们就会被存储在squarescubes变量中,并计算和打印最终输出。该程序将打印

Final output 1536  

死锁

使用Channel时要考虑的一个重要因素是死锁。如果一个 Goroutine 正在Channel上发送数据,那么预计其他一些 Goroutine 应该正在接收数据。如果这没有发生,那么程序将在运行时出现Deadlock

类似地,如果一个 Goroutine 正在等待从某个Channel接收数据,那么其他一些 Goroutine 就应该在该Channel上写入数据,否则程序将会出现Deadlock

package mainfunc main() {  ch := make(chan int)ch <- 5
}

Run program in playground

在上面的程序中,ch创建了一个Channel,我们在第6 行发送5到该Channel。在此程序中,没有其他 Goroutine 正在从Channel接收数据。因此,该程序将因以下运行时错误而发生恐慌。

fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:  
main.main()  /tmp/sandbox046150166/prog.go:6 +0x50

单向Channel

到目前为止我们讨论的所有Channel都是双向Channel,即数据可以在它们上发送和接收。还可以创建单向Channel,即仅发送或接收数据的Channel。

package mainimport "fmt"func sendData(sendch chan<- int) {  sendch <- 10
}func main() {  sendch := make(chan<- int)go sendData(sendch)fmt.Println(<-sendch)
}

Run program in playground

在上面的程序中,我们sendch在第 10 行创建仅发送Channel。chan<- int箭头指向 时表示仅发送Channel。我们尝试从在的仅发送Channel接收数据。这是不允许的,当程序运行时,编译器会,

./prog.go:12:14:无效操作:<-sendch(从仅发送类型 chan<- int 接收)

一切都很好,但如果无法读取,写入仅发送Channel有什么意义!

这就是Channel转换发挥作用的地方。可以将双向Channel转换为仅发送或仅接收Channel,但反之则不然。

package mainimport "fmt"func sendData(sendch chan<- int) {  sendch <- 10
}func main() {  chnl := make(chan int)go sendData(chnl)fmt.Println(<-chnl)
}

Run program in playground

上面程序的在10行号中。chnl创建了一个双向Channel。它作为参数传递给sendData Goroutine。. 该sendData函数在第 6行将此Channel转换为仅发送Channel。所以现在Channel仅在sendDataGoroutine 内部发送,但在主 Goroutine 中是双向的。该程序将打印10为输出。

关闭Channel和Channel上的范围循环

发送方能够关闭Channel,以通知接收方不再有数据在Channel上发送。

接收者在从Channel接收数据时可以使用附加变量来检查Channel是否已关闭。

v, ok := <- ch  

ok如果通过成功发送到Channel的操作接收到该值,则上述语句为 true。如果ok为 false,则意味着我们正在从封闭的Channel中读取数据。从关闭的Channel读取的值将是该Channel类型的零值。例如,如果Channel是一个intChannel,那么从关闭的Channel接收到的值将为0

package mainimport (  "fmt"
)func producer(chnl chan int) {  for i := 0; i < 10; i++ {chnl <- i}close(chnl)
}
func main() {  ch := make(chan int)go producer(ch)for {v, ok := <-chif ok == false {break}fmt.Println("Received ", v, ok)}
}

Run program in playground

在上面的程序中,producerGoroutine 将 0 到 9 写入chnlChannel,然后关闭Channel。main 函数for在第 16 行有一个无限循环,它使用第 16 行中的变量检查Channel是否关闭ok。如果ok为 false,则表示Channel已关闭,因此循环已中断。ok否则打印接收到的值和 的值。该程序打印,

Received  0 true  
Received  1 true  
Received  2 true  
Received  3 true  
Received  4 true  
Received  5 true  
Received  6 true  
Received  7 true  
Received  8 true  
Received  9 true  

for循环的for range形式可用于从Channel接收值,直到Channel关闭为止。

让我们使用 for range 循环重写上面的程序。

package mainimport (  "fmt"
)func producer(chnl chan int) {  for i := 0; i < 10; i++ {chnl <- i}close(chnl)
}
func main() {  ch := make(chan int)go producer(ch)for v := range ch {fmt.Println("Received ",v)}
}

Run program in playground

第 16 行中的循环for range。 从Channel接收数据ch直至关闭。一旦ch关闭,循环就会自动退出。该程序输出,

Received  0  
Received  1  
Received  2  
Received  3  
Received  4  
Received  5  
Received  6  
Received  7  
Received  8  
Received  9  

可以使用 for range 循环重写Channel部分的另一个示例中的程序,以提高代码可重用性。

如果仔细观察该程序,您会发现查找数字的各个数字的代码在calcSquares函数和calcCubes函数中都重复出现。我们将该代码移至其自己的函数中并同时调用它。

package mainimport (  "fmt"
)func digits(number int, dchnl chan int) {  for number != 0 {digit := number % 10dchnl <- digitnumber /= 10}close(dchnl)
}
func calcSquares(number int, squareop chan int) {  sum := 0dch := make(chan int)go digits(number, dch)for digit := range dch {sum += digit * digit}squareop <- sum
}func calcCubes(number int, cubeop chan int) {  sum := 0dch := make(chan int)go digits(number, dch)for digit := range dch {sum += digit * digit * digit}cubeop <- sum
}func main() {  number := 589sqrch := make(chan int)cubech := make(chan int)go calcSquares(number, sqrch)go calcCubes(number, cubech)squares, cubes := <-sqrch, <-cubechfmt.Println("Final output", squares+cubes)
}

Run program in playground

上面程序中的函数digits现在包含从数字中获取各个数字的逻辑,并且由 和calcSquares函数calcCubes同时调用。一旦号码中不再有数字,则第13 行Channel将关闭。.calcSquarescalcCubesGoroutine 使用for range循环监听各自的Channel,直到关闭。程序的其余部分是相同的。该程序还将打印

Final output 1536  

本教程到此结束。Channel中还有一些概念,例如缓冲Channel、工作池和select。我们将在他们自己的单独教程中讨论它们。谢谢阅读。祝你有美好的一天。

http://www.dt0577.cn/news/41451.html

相关文章:

  • 谷城网站制作好的搜索引擎推荐
  • 网站首页怎么做友链外链app
  • 可以做业务推广的网站有哪些内容seo
  • 张店网站推广谷歌优化怎么做
  • 邢台做网站口碑好网站主页
  • 备案号 不放在网站首页搜搜
  • 手机网站模版宁波seo推广优化
  • 北京成交型网站建设价格全国疫情地区查询最新
  • wordpress符号seo优化排名易下拉效率
  • 做卫生用品都在什么网站上海排名优化seo
  • java企业网站健康码防疫核验一体机
  • 个人网站设计与开发论文百度竞价托管靠谱吗
  • 廊坊网站建设冀icp备重庆发布的最新消息今天
  • 南昌网站定制公司哪家好seo建站需求
  • 界面设计ui东莞市网站seo内容优化
  • 做网站点击挣钱不?网络营销专业是做什么的
  • 学生做的网站海外域名
  • 阐述网站建设的步骤过程色盲测试图片60张
  • 网站建设毕业设计怎么做软文怎么写
  • 海南省住房和城乡建设局网站seo营销的概念
  • 易语言怎么做ifa网站填表长沙网站seo哪家公司好
  • 潍坊网站模板在哪百度快照官网
  • dw中用php做网站商洛网站建设
  • 个人网站备案可以填几个域名知名品牌营销策划案例
  • 历下区网站建设公司站长工具视频
  • 做服装团购有哪些网站2020站群seo系统
  • 网站推广的具体内容app代理推广平台
  • 网站建设中心seo整站优化吧
  • 手机网站营销百度seo公司整站优化
  • 朋友圈网站文章怎么做的搜狗收录批量查询