并发——轻量级线程,通道,单向通道(代码片段)

acgame acgame     2022-12-23     311

关键词:

1、轻量级线程

goroutine 是 Go语言中的轻量级线程实现,由 Go 运行时(runtime)管理。Go 程序会智能地将 goroutine 中的任务合理地分配给每个 CPU。
Go 程序从 main 包的 main() 函数开始,在程序启动时,Go 程序就会为 main() 函数创建一个默认的 goroutine。

1)使用普通函数创建goroutine

Go 程序中使用 go 关键字为一个函数创建一个 goroutine。一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。

为一个普通函数创建 goroutine 的写法如下:

go 函数名( 参数列表 )

  • 函数名:要调用的函数名。
  • 参数列表:调用函数需要传入的参数。

使用 go 关键字创建 goroutine 时,被调用函数的返回值会被忽略。

如果需要在 goroutine 中返回数据,通过通道把数据从 goroutine 中作为返回值传出。

2)使用匿名函数创建goroutine

go 关键字后也可以为匿名函数或闭包启动 goroutine。

使用匿名函数或闭包创建 goroutine 时,除了将函数定义部分写在 go 的后面之外,还需要加上匿名函数的调用参数,格式如下:

go func( 参数列表 )
    函数体
( 调用参数列表 )

其中:

  • 参数列表:函数体内的参数变量列表。
  • 函数体:匿名函数的代码。
  • 调用参数列表:启动 goroutine 时,需要向匿名函数传递的调用参数。

 

2、通道

Go语言提倡使用通信的方法代替共享内存,当一个资源需要在 goroutine 之间共享时,通道在 goroutine 之间架起了一个管道,并提供了确保同步交换数据的机制。声明通道时,需要指定将要被共享的数据的类型。可以通过通道共享内置类型、命名类型、结构类型和引用类型的值或者指针。

Go语言中的通道(channel)是一种特殊的类型。在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。goroutine 间通过通道就可以通信。
通道像一个传送带或者队列,总是遵循先入先出的规则,保证收发数据的顺序。

1)声明通道类型

通道本身需要一个类型进行修饰,就像切片类型需要标识元素类型。通道的元素类型就是在其内部传输的数据类型,声明如下:

var 通道变量 chan 通道类型

  • 通道类型:通道内的数据类型。
  • 通道变量:保存通道的变量。

chan 类型的空值是 nil,声明后需要配合 make 后才能使用。

2)创建通道

通道是引用类型,需要使用 make 进行创建,格式如下:

通道实例 := make(chan 数据类型)

  • 数据类型:通道内传输的元素类型。
  • 通道实例:通过make创建的通道句柄。

3)使用通道发送数据

通道的发送使用特殊的操作符<-,将数据通过通道发送的格式为:通道变量 <- 值

  • 通道变量:通过make创建好的通道实例。
  • 值:可以是变量、常量、表达式或者函数返回值等。值的类型必须与ch通道的元素类型一致。

把数据往通道中发送时,如果接收方一直都没有接收,那么发送操作将持续阻塞。

4)使用通道接收数据

通道接收同样使用<-操作符,通道接收有如下特性:

  •  通道的收发操作在不同的两个 goroutine 间进行。由于通道的数据在没有接收方处理时,数据发送方会持续阻塞,因此通道的接收必定在另外一个 goroutine 中进行。
  • 接收将持续阻塞直到发送方发送数据。如果接收方接收时,通道中没有发送方发送数据,接收方也会发生阻塞,直到发送方发送数据为止。
  • 每次接收一个元素。通道一次只能接收一个数据元素。

通道的数据接收的4种写法:

阻塞接收数据:

阻塞模式接收数据时,将接收变量作为<-操作符的左值,格式如下:

data := <-ch

执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。

 

非阻塞接收数据:

使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下:

data, ok := <-ch

  • data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
  • ok:表示是否接收到数据。

非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要实现接收超时检测,可以配合 select 和计时器 channel 进行。

 

接收任意数据,忽略接收的数据:

阻塞接收数据后,忽略从通道返回的数据,格式如下:

<-ch

执行该语句时将会发生阻塞,直到接收到数据,但接收到的数据会被忽略。

 

循环接收:

通道的数据接收可以借用 for range 语句进行多个元素的接收操作,格式如下:

for data := range ch

通道 ch 是可以进行遍历的,遍历的结果就是接收到的数据。数据类型就是通道的数据类型。通过 for 遍历获得的变量只有一个,即上面例子中的 data。

 

3、单向通道

Go语言的类型系统提供了单方向的 channel 类型,顾名思义,单向 channel 只能用于发送或者接收数据。channel 本身必然是同时支持读写的,否则根本没法用。
假如一个 channel 真的只能读,那么肯定只会是空的,因为你没机会往里面写数据。同理,如果一个 channel 只允许写,即使写进去了,也没有丝毫意义,因为没有机会读取里面的数据。所谓的单向 channel 概念,其实只是对 channel 的一种使用限制。

1)单向通道的声明

我们在将一个 channel 变量传递到一个函数时,可以通过将其指定为单向 channel 变量,从而限制该函数中可以对此 channel 的操作。

单向 channel 变量的声明非常简单,只能发送的通道类型为chan<-,只能接收的通道类型为<-chan,格式如下:

var 通道实例 chan<- 元素类型    // 只能发送通道
var 通道实例 <-chan 元素类型    // 只能接收通道

  • 元素类型:通道包含的元素类型。
  • 通道实例:声明的通道变量。

2)关闭channel

关闭 channel 非常简单,直接使用 Go语言内置的 close() 函数即可:close(ch)

 

 

 

 

go语言并发与通道的运用(代码片段)

在go语言中我们可以使用goroutine开启并发。goroutine是轻量级线程,goroutine的调度是由Golang运行时进行管理的。goroutine语法格式:go函数名(参数列表)实例1:packagemainimport("fmt""time")funcsay(sstring)fori:=0;i< 查看详情

golang✔️走进go语言✔️第十六课协程&通道(代码片段)

...)协程协程(Coroutine)是一种基于线程之上,但又比线程更加轻量级的存在.一个进程可以拥有多个线程,一个线程也可以拥有多个协程.协程拥有高并发,高I/O,低计算. 查看详情

golang✔️走进go语言✔️第十六课协程&通道(代码片段)

...)协程协程(Coroutine)是一种基于线程之上,但又比线程更加轻量级的存在.一个进程可以拥有多个线程,一个线程也可以拥有多个协程.协程拥有高并发,高I/O,低计算. 查看详情

kotlin协程协程并发安全问题(使用atomic并发安全类型|使用channel通道|使用mutext轻量级锁|使用semaphore轻量级信号量)(代码片段)

...使用Atomic并发安全类型三、使用Channel通道四、使用Mutext轻量级锁五、使用Semaphore轻量级信号量一、协程不安全数据访问在多个线程中同时访问相同数据,就会出现线程不安全访问的问题;如果多个协程中,同时访问相同数据,同样会... 查看详情

goplgoroutine和通道(代码片段)

Go语言的并发编程风格Go有两种并发编程风格:goroutine和通道(chennle),支持通信顺序进程(CommunicatingSequentialProcess,CSP),CSP是一个并发的模式,在不同的执行体(goroutine)之间传递值,但是变量本身局限于单一的执行体。共享... 查看详情

go语言之并发编程channel

单向channel:单向通道可分为发送通道和接收通道。但是无论哪一种单向通道,都不应该出现在变量的声明中,假如初始化了这样一个变量varuselessChanchan<-int=make(chan<-int,10)这样一个变量该如何使用呢,这样一个只进不出的通道... 查看详情

go笔记(十四):通道channel(代码片段)

...utine)之间的数据共享,保证数据同步交换的机制。协程是轻量级线程,类似于Java中的线程。2、通道的类型2.1、无缓冲通道  用于同步通信,可保证在发送和接收数据时完成两个goroutine(协程)的数据交换。2.2、缓冲通道  用... 查看详情

javanio管道(代码片段)

JavaNIO 管道是两个线程之间的单向数据连接。Pipe有一个source通道和sink通道(内部类)。数据会被写到sink通道,从source通道读取。给一张Pipe通道的原理图:  创建管道:Pipepipe=Pipe.open(); 向管道写数据:Pipe.SinkChannel... 查看详情

nio之管道(pipe)(代码片段)

JavaNIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。代码使用示例:1@Test2publicvoidtestPipe()throwsIOException3//1、获取通道4Pipepipe=Pipe.open();56//2、获取sink管道,用... 查看详情

go36-10,11-通道(代码片段)

通道通道(channel)是Go语言的并发编程模式中重要的一员。通道类型的值本身就是并发安全的,这也是Go语言自带的、唯一一个可以满足并发安全性的类型。使用通道声明一个通道类型变量,需要确定该通道类型的元素类型,这... 查看详情

javanio之pipe(代码片段)

1、简介管道是2个线程之间的单向数据连接一个source通道(读取)和一个sink通道(写入)1.1、常用方法打开管道Pipepipe=Pipe.open(); 写入管道需要访问sink通道Pipe.SinkChannelsinkChannel=pipe.sink();读取数据需要访问sour... 查看详情

如何正确使用通道来控制并发?(代码片段)

我是Go的并发新手,我正试图弄清楚如何使用通道来控制并发。我想做的是有一个循环,我可以使用一个新的go例程调用一个函数,并在该函数处理时继续循环,我想限制运行到3的例程的数量。我的第一次尝试这样做是下面的代... 查看详情

go语言通道(代码片段)

...以供多个线程来使用。这种方法思路简单,但却使得并发控制变得复杂和低效。Golang不建议使用这种方式&#x 查看详情

11nio--管道pipe(代码片段)

 管道(Pipe)JavaNIO管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。  @Testpublicvoidtest()throwsIOException//1、获取管道Pipepipe=Pipe.open();//2、将缓冲区的数据写... 查看详情

第153篇solidity中支付通道的实现(代码片段)

1.单向支付通道支付通道允许参与者重复transferEther 。以下是本合约的使用方法:Alice部署了合约,用Ether 为其提供资金;Alice通过签署消息(链外)授权付款,并将签名发送给Bob;Bob通过向智能合约提交签名信息来要求付... 查看详情

nioselector(选择器)(代码片段)

...ventLoop聚合了Selector(选择器,也叫多路复用器),可以同时并发处理成百上千个客户端连接。 2)当线程从某客户端Socket通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。 3)线程通常将非阻塞IO的空闲时间... 查看详情

rabbitmq-关闭空闲/悬空通道(代码片段)

我有一个多线程应用程序,它将传入的消息发布到rabbitmq交换。使用rabbitmqjava客户端,我在应用程序启动时创建一个rabbitmq连接,并在我的所有线程中共享它。每个线程都会创建一个新通道(threadlocal),以便不按照rabbitmq文档的... 查看详情

云原生时代崛起的编程语言go并发编程实战(代码片段)

Go语言是天然并发利器,通过通信来实现内存共享而不是通过共享内存来通信,本篇从了解Go的并发哲学、理论及并发原语开始,之后用一个个Go代码示例认识Go的协程、通道、定时器、互斥锁、池化、原生操作等十几个并发编程... 查看详情