首页>>后端>>Golang->gochannel并发?

gochannel并发?

时间:2023-12-02 本站 点击:0

gochannel过期时间

Go语言中的go-channel是一种很常用的并发通信方式,通过它可以实现协程之间的数据传输与同步,常常用于协程池、事件驱动、生产者-消费者模式等场景。

在Go语言中,go-channel并不支持设置过期时间,即无法直接通过给channel设置一个过期时间来控制其失效。但是可以通过其他技巧来达到类似的效果。

一种常用的技巧是在channel中传递一个结构体,该结构体中包含一个数据字段和一个time.Time类型的字段,表示数据产生的时间。在读取channel数据时,可以判断数据产生的时间是否已经过期,如果过期就直接丢弃该数据。

例如:

```go

type Data struct {

Value interface{}

ExpireAt time.Time // 数据失效时间

}

ch := make(chan Data)

// 数据写入通道,限制数据有效期10秒钟

go func() {

data := Data{Value: "hello", ExpireAt: time.Now().Add(10 * time.Second)}

ch - data

}()

// 读取通道数据

// 如果当前时间已经超过数据的失效时间,就直接丢弃该数据

// 否则就输出该数据

for {

select {

case data := -ch:

if time.Now().After(data.ExpireAt) {

continue // 已经过期,丢弃该数据

}

fmt.Println(data.Value) // 输出数据

}

}

```

这种方式虽然不是直接控制channel的过期时间,但通过控制传递的数据来达到类似的效果,是一种常用的解决方案。同时需要注意的是,如果通道中的元素被垃圾回收器所移除,那么可能被只包含指针的数据结构的通道就成为了正常的空闲物理内存的一部分,通道的元素也就永远无法失效了。因此在需要实现具有失效时间特性的通道时,需要特别注意内存管理问题。

Go channel 实现原理分析

channel一个类型管道,通过它可以在goroutine之间发送和接收消息。它是Golang在语言层面提供的goroutine间的通信方式。Go依赖于成为CSP的并发模型,通过Channel实现这种同步模式。Golang并发的核心哲学是不要通过共享内存进行通信。

下面Go通过channel来实现通信例子:

终端显示结果:

上面的例子只输出goRoutineA信息,没有执行goRoutineB说明channel仅允许被一个goroutine读写。

下面通过源码程序执行过程分析,如果对go并发和调度相关知识不了解,可以 预览这里

首先我们看下通道的结构hchan,源码再src/runtime/chan.go下

创建两种channel类型,一个带缓冲区和一个不带缓冲区的channel

创建通道后的缓冲通道结构

源码在$GOPATH/src/runtime/chan.go下:

创建一个带有buffer的channel,底层的数据结构模型如图:

向channel中写入数据

底层hchan数据流程下如图:

发送操作步骤:

执行流程图如下:

从channel中读取数据操作几乎和写入操作雷同

底层hchan数据流转如下图:

读数据操作如下:

大概流程如下:

recvq和sendq基本上是链表,基本如下:

select 就是用来监听和channel有关的IO操作,当前IO操作发生触发相关动作执行

如下例子:

多次执行后的结果如下:

select 语句会阻塞,知道监测到一个可执行的IO操作为止,goRoutineD和goRoutineE睡眠时间相同,都是3s,从输出可以看出,从channel中读取数据顺序是随机的。

可以持续冲channel中读取数据,一直到channel被关闭,当channel中没有数据是会阻塞当前goroutine,这里阻塞和读channel时阻塞处理机制一样。

例子如下:

运行结果如下:

死锁是指两个或者两个以上的协程在执行任务过程中,由于竞争资源或者彼此通信而造成的一种阻塞现象。在非缓冲信道如发生只流入不流出或者只流入出不流入就会发生死锁

死锁例子如下:

向非缓冲区通道读取数据会发生阻塞导致死锁,解决办法开启缓冲区,先向channel中写入数据

写入数据超过缓冲区数量也会发生死锁,解决办法将写入数据取走

向关闭的channel写入数据。解决办法别向关闭的channel写入数据。

可以参考更多死锁例子:

Go CSP并发模型

Go的CSP并发模型

Go实现了两种并发形式。第一种是大家普遍认知的:多线程共享内存。其实就是Java或者C++等语言中的多线程开发。另外一种是Go语言特有的,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。

CSP 是 Communicating Sequential Process 的简称,中文可以叫做通信顺序进程,是一种并发编程模型,由 Tony Hoare 于 1977 年提出。简单来说,CSP 模型由并发执行的实体(线程或者进程)所组成,实体之间通过发送消息进行通信,这里发送消息时使用的就是通道,或者叫 channel。CSP 模型的关键是关注 channel,而不关注发送消息的实体。 Go 语言实现了 CSP 部分理论 。

“ 不要以共享内存的方式来通信,相反, 要通过通信来共享内存。”

Go的CSP并发模型,是通过 goroutine和channel 来实现的。

goroutine 是Go语言中并发的执行单位。其实就是协程。

channel是Go语言中各个并发结构体(goroutine)之前的通信机制。 通俗的讲,就是各个goroutine之间通信的”管道“,有点类似于Linux中的管道。

Channel

Goroutine

Go入门: 浅谈channel

channel 管道在golang中是一个非常重要的概念,我之前模糊不清,对于 "输入管道" "输出管道" 所用到的 - - 经常分不清楚。

channel 是 goroutine 之间通信的一种方式,可以类比成 Unix 中的进程的通信方式管道。

channel 提供了一种通信机制,通过它,一个 goroutine 可以想另一 goroutine 发送消息。channel 本身还需关联了一个类型,也就是 channel 可以发送数据的类型。例如: 发送 int 类型消息的 channel 写作 chan int 。

channel在glang中实现了下面的一些功能:

1 数据交流:当作并发的 buffer 或者 queue,解决生产者 - 消费者问题。多个 goroutine 可以并发当作生产者(Producer)和消费者(Consumer)。

2 数据传递:一个 goroutine 将数据交给另一个 goroutine,相当于把数据的拥有权 (引用) 托付出去。

3 信号通知:一个 goroutine 可以将信号 (closing、closed、data ready 等) 传递给另一个或者另一组 goroutine 。

4 任务编排:可以让一组 goroutine 按照一定的顺序并发或者串行的执行,这就是编排的功能。

5 锁:利用 Channel 也可以实现互斥锁的机制。

channel 分: "只能接收" , “只能发送”, “可以接收也可以发送” 三种类型

//声明一个channel,这个channel只能保存int类型的数据。也就是说一端只能channel中写入int型的数据,另一段只能从channel中读取int型数据

关闭channel时,需注意:

从无缓存的 channel 中读取消息会 阻塞 ,直到有 goroutine 向该 channel 中发送消息;同理,向无缓存的 channel 中发送消息也会阻塞,直到有 goroutine 从 channel 中读取消息。

有缓存的 channel 的声明方式为指定 make 函数的第二个参数,该参数为 channel 缓存的容量

有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息。

Golang入门到项目实战 | golang并发变成之通道channel

Go提供了一种称为通道的机制,用于在goroutine之间共享数据。当您作为goroutine执行并发活动时,需要在goroutine之间共享资源或数据,通道充当goroutine之间的管道(管道)并提供一种机制来保证同步交换。

根据数据交换的行为,有两种类型的通道:无缓冲通道和缓冲通道。无缓冲通道用于执行goroutine之间的同步通信,而缓冲通道用于执行异步通信。无缓冲通道保证在发送和接收发生的瞬间两个goroutine之间的交换。缓冲通道没有这样的保证。

通道由make函数创建,该函数指定chan关键字和通道的元素类型。

这是创建无缓冲和缓冲通道的代码块:

语法

使用内置函数make创建无缓冲和缓冲通道。make的第一个参数需要关键字chan,然后是通道允许交换的数据类型。

这是将值发送到通道的代码块需要使用-运算符:

语法

一个包含5个值的缓冲区的字符串类型的goroutine1通道。然后我们通过通道发送字符串“Australia”。

这是从通道接收值的代码块:

语法

- 运算符附加到通道变量(goroutine1)的左侧,以接收来自通道的值。

在无缓冲通道中,在接收到任何值之前没有能力保存它。在这种类型的通道中,发送和接收goroutine在任何发送或接收操作完成之前的同一时刻都准备就绪。如果两个goroutine没有在同一时刻准备好,则通道会让执行其各自发送或接收操作的goroutine首先等待。同步是通道上发送和接收之间交互的基础。没有另一个就不可能发生。

在缓冲通道中,有能力在接收到一个或多个值之前保存它们。在这种类型的通道中,不要强制goroutine在同一时刻准备好执行发送和接收。当发送和接收阻塞时也有不同的条件。只有当通道中没有要接收的值时,接收才会阻塞。仅当没有可用缓冲区来放置正在发送的值时,发送才会阻塞。

实例

运行结果


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/10066.html