处理Golang的Goroutines和频道并发
#编程 #go #并发性

goroutines和并发

编程中的并发是计算机程序一次执行多个指令/任务的能力。随着并发的长期运行,任务不会承担该程序中的其他任务,因此,在程序的其余部分继续进行时,长期运行的任务可以单独运行。总而言之,并发性是任务不必等到另一个任务完成之前才能运行之前。这样可以确保快速有效地执行程序。

不同的编程语言具有不同的处理并发使用的方法,可以使用Goroutines处理它,Goroutine是GO编程语言中的轻巧执行线程,并且与主程序流同时执行的函数。与传统线程相比,它们在程序上的开销较少(这也可以处理并发),因此是GO编程中的流行选择。

创建一个goroutine

go go例程是正常的函数,但用go the关键字调用,基本上任何功能都可以变成goroutine,

示例:

func helloWorld(str string) {
    for i := 0; i < 6; i++ {
    fmt.Println(str, ":", i)
    }
}

func main() {
    go helloWorld("Hello World")
    time.Sleep(1 * time.Second)
}

在这里,我们有一个包含三个goroutines的程序,这是一个主函数,它是一个例程,使用go关键字在主函数内部调用的两个helloworld函数。 Helloworld Goroutine打印出“ Hello World”和“ Hello World”五次。

注意time.Sleep(1 * time.Second)in the主函数,它会延迟该功能一秒到下一行并完成程序。

什么是频道,它们用什么?

频道就像goroutines之间的管道一样,它们为戈列尼提供了一种有效互动的方式,渠道是将特定类型的数据从一种数据类型发送到另一种数据类型的一种方式。

我们使用make方法与类型chan创建频道,然后是您希望频道在make()方法中作为参数发送的数据类型;

var channel = make(chan int)

这是使用频道的示例程序;

package main

import (
    "fmt"

func sendInteger(myIntChannel chan int){
    for i:=1; i<6; i++ {
      myIntChannel <- i // sending value
    }
  }

func main() {
    myIntChannel := make(chan int)
    go sendInteger(myIntChannel) 
for i:=1; i<6; i++ {
  message := <-myIntChannel //receiving value
      fmt.Println(message) 
    }
}

发送和接收频道的值

我们在主函数中创建频道myIntChannel,然后将其传递到sendInteger goroutine中,我们使用频道在特殊左点箭头的左侧发送数字1-5,并将其值想要在箭头的右侧发送。然后,我们在主函数中接收从sendInteger Goroutine发送的值,但是这次频道位于箭头的右侧,并在同时运行的两个函数中打印出发送的值。

使用频道发送和接收数据时要注意的一件事是阻止程序,即阻止程序,像message := <-myIntChannel这样的语句通过渠道接收数据将阻止,直到他们收到数据和发送数据的语句也将阻止接收器准备就绪。

通道方向

可以指定频道,即指定用于发送或接收数据,我们可以在要使用的函数参数中使用<-箭头和chan关键字来执行此操作。

func sendInteger(myIntChannel chan <- int){ //send-only channel---the left arrow on the right side of the "chan" keyword in the function's arguments specifies a send only channel

    for i:=1; i<=50; i++ {
     myIntChannel <- i // sending value
    }
    
}

func printer(myIntChannel <- chan int)  { //receive-only channel---the left arrow on the left side of the "chan" keyword in the function's arguments specifies a receive only channel
    for i:=1; i<=50; i++ {
        message := <-myIntChannel //receiving value
        fmt.Println(message) 
    }
}

func main() {
    myIntChannel := make(chan int)
    go sendInteger(myIntChannel) 
    go printer(myIntChannel)
    time.Sleep(1 * time.Second)
}

选择语句

选择的语句几乎与GO中的Switch语句相同,它们都是有条件地执行语句的目的,但是SELECT语句对频道更特定,它们可以在通道实现条件时执行操作。

示例:

func sendValuesFast(myStringChannel1 chan string){
      time.Sleep(5 * time.Millisecond)
      myStringChannel1 <- "Fast" // sending value
}

func sendValuesSlow(myStringChannel2 chan string){
     time.Sleep(30 * time.Millisecond)
      myStringChannel2 <- "Slow" // sending value
    
}

func main() {
   myStringChannel1 := make(chan string)
   myStringChannel2 := make(chan string)

    go sendValuesFast(myStringChannel1) 
    go sendValuesSlow(myStringChannel2)

    select{
    case res:= <- myStringChannel1:
          fmt.Println("sendValuesFast finished first",res)
    case res:= <- myStringChannel2:
        fmt.Println("sendValuesSlow finished first",res)
    }
}

在此示例中,我们在sendvaluesfast和sendvaluesslow goroutines中有两个频道,我们使用time.Sleep()延迟到mystringChannel2,因此MystringChannel首先完成,并且在Select语句中完成了第一种情况,并且执行了Select Cance。 >

缓冲通道

到目前为止必须等到有一个陈述才能收到它。

再次发送。

另一方面,使用make()方法中的内存分配创建

缓冲通道,并且只有在通道已满(发送时)或频道为空(接收时)时才会阻止。它允许您存储创建上指定的数据量,例如channel:=make(chan int, 5)创建一个可以存储5个整数的频道,并且如果发送了第6个频道,则频道将阻止,直到读取频道中的消息。

func bufferFunction(bufferChannel chan int)  {
    for i := 1; i<=6; i++ { 
        bufferChannel <- i
        time.Sleep(1 * time.Second)
        fmt.Println("Channel sent", i)
    }
}

func main()  {
   bufferChannel:= make(chan int,5)
   bufferFunction(bufferChannel)
}

在这里,我们有一个示例的示例缓冲通道,带有5个整数的空间,我们使用for loop尝试发送数字1-6,我们在没有接收语句的情况下执行此操作,因此,当循环试图发送第六个整数时频道块和程序完成。

本文是为了帮助我更好地理解goroutines和频道,剧透警报:我仍然不了解它们!