教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go并发编程——channel

Go并发编程——channel

发布时间:2022-01-17   编辑:jiaochengji.com
教程集为您提供Go并发编程——channel等资源,欢迎您收藏本站,我们将为您提供最新的Go并发编程——channel资源

以前从未接触过并发编程,所以,且写且学吧

<h3>引入channel</h3>

<pre code_snippet_id="112456" snippet_file_name="blog_20131214_1_9998576" name="code" class="cpp">package main import ( "fmt" "sync" "runtime" ) var counter int = 0 func Count(lock *sync.Mutex){ lock.Lock() counter fmt.Println(counter) lock.Unlock() } func main(){ lock := &sync.Mutex{} for i:=0;i<100;i { go Count(lock) } for{ lock.Lock() c:=counter lock.Unlock() runtime.Gosched() if c>=100{ break } } } </pre>
将counter从0加至10

但是上面的做法太过复杂,一直对lock进行引用,所以引用channel


<pre code_snippet_id="112456" snippet_file_name="blog_20131214_2_5778454" name="code" class="cpp">package main import "fmt" func Count(ch chan int){ ch <- 1 fmt.Println("Counting") } func main(){ chs := make([]chan int, 10) for i:=0;i<10;i { chs[i]=make(chan int) go Count(chs[i]) } for _,ch := range(chs){ <-ch } fmt.Println(chs) }</pre>
简单的解释是,我们通过ch <- 1语句向对应的channel中写入一个数据。在这个channel被读取前,这个操作是阻塞的。

在所有的goroutine启动完成后,我们通过<-ch语句从10个channel中依次读取数据。在对应的channel写入数据前,这个操作也是阻塞的。

从而使用这个操作替代了锁的使用。


下面对channel进行详细介绍:

<h4><span style="color:#993399">1.基本语法:</span></h4>

声明一个channel

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_3_7165987" name="code" class="cpp">var ch chan int var m map[string] chan bool</pre>

定义一个channel

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_4_8420506" name="code" class="cpp">s := make(chan int)</pre>

在channel的用法中,最常见的包括写入和读出。将一个数据写入(发送)至channel的语法很直观,如下:

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_5_2498925" name="code" class="cpp">ch <- value</pre>

向channel写入数据通常会导致程序阻塞,直到有其他goroutine从这个channel中读取数据。从channel中读取数据的语法是

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_6_6020935" name="code" class="cpp">value := <-ch</pre>

如果channel之前没有写入数据,那么从channel中读取数据也会导致程序阻塞,直到channel中被写入数据为止。

<h4><span style="color:#993399">2.select:</span></h4>

select 用于监控一系列文件文件句柄,一旦其中一个文件句柄发生了IO操作,该select()调用就会被返回

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_7_1179149" name="code" class="cpp">//这里注意,一定要定义channel之后才能使用 ch := make(chan int, 1) for { select { case ch <- 0: case ch <- 1: } i := <-ch fmt.Println("Value received:", i) }</pre><span style="color:#993399">
</span>

<h4><span style="color:#993399">3.缓冲机制:</span></h4>

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_8_4385515" name="code" class="cpp">c := make(chan int, 1024)</pre>
这样子即使没有读取方,可以一直向channel中写入,直至缓冲区被填满

可以使用range关键来实现更为简便的循环读取:

<span style="color:#CC0000">这里不知道为什么总是会出错!!!!</span>

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_9_7243217" name="code" class="cpp">for i := range c{ fmt.Println(i) }</pre>
总体程序

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_10_9685432" name="code" class="cpp"> c := make(chan int, 10)  for i:=0;i<10;i { c<-12 }  fmt.Println(len(c)) for j := range c{ fmt.Println(j) }</pre>

<h4><span style="color:#993399">4.超时机制:</span></h4>

在并发编程的通信过程中,最需要处理的就是超时问题,即向channel写数据时发现channel已满,

或者从channel试图读取数据时发现channel为空。

如果不正确处理这些情况,很可能会导致整个goroutine锁死.即deadlock发生!

i:= <-ch

这个语句在ch中有值写入时,没有问题,一旦ch中为空,没有值写入,会出现死锁。

故而,超时是一个非常实际的方法,在Go语言中,主要是借用select语句进行模拟超时

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_11_2019747" name="code" class="cpp">timeout := make(chan bool,1) ch :=make(chan int) go func(){ time.sleep(1) timeout<-true }() select{ case <-ch: case <-timeout: }</pre>

<h4>5.单向channel:</h4>

单向channel变量的声明

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_12_2510115" name="code" class="cpp">var ch1 chan int // ch1是一个正常的channel,不是单向的 var ch2 chan<- float64// ch2是单向channel,只用于写float64数据 var ch3 <-chan int // ch3是单向channel,只用于读取int数据</pre>

单向channel的初始化

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_13_7876072" name="code" class="cpp">ch4 := make(chan int) ch5 := <-chan int(ch4) // ch5就是一个单向的读取channel ch6 := chan<- int(ch4) // ch6 是一个单向的写入channel</pre>

使用方法

<pre code_snippet_id="112456" snippet_file_name="blog_20131222_14_8017776" name="code" class="cpp">func Parse(ch <-chan int) { for value := range ch { fmt.Println("Parsing value", value) } }</pre>

<h4>6.关闭channel</h4>

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

判断一个channel是否已经被关闭,可以在读取的时候使用多重返回值的方式:
x, ok := <-ch
第二个bool返回值是false则表示ch已经被关闭






到此这篇关于“Go并发编程——channel”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
mysql导入导出数据时中文乱码的解决办法
PHP无限级分类菜单实例程序
MySQL中group_concat函数使用例子
Go并发编程——channel
图解 Go 并发编程
更改MySQL数据库名实例代码
使用SHOW PROFILE查找MySQL中的SQL耗时瓶颈
js时间函数综合例子(日期计算、字符串转日期等)
专家教你如何有效的学习Drupal - Drupal问答
golang学习笔记(二)—— 深入golang中的协程

[关闭]
~ ~