mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 11:44:20 +08:00
rebuild
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Goroutines | Go编程语言</title>
|
||||
<title>Goroutines | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.1" data-chapter-title="Goroutines" data-filepath="ch8/ch8-01.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.1" data-chapter-title="Goroutines" data-filepath="ch8/ch8-01.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>示例: 併發的Clock服務 | Go编程语言</title>
|
||||
<title>示例: 併發的Clock服務 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.2" data-chapter-title="示例: 併發的Clock服務" data-filepath="ch8/ch8-02.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.2" data-chapter-title="示例: 併發的Clock服務" data-filepath="ch8/ch8-02.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>示例: 併發的Echo服務 | Go编程语言</title>
|
||||
<title>示例: 併發的Echo服務 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.3" data-chapter-title="示例: 併發的Echo服務" data-filepath="ch8/ch8-03.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.3" data-chapter-title="示例: 併發的Echo服務" data-filepath="ch8/ch8-03.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -2024,7 +2024,91 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="83-示例-併發的echo服務">8.3. 示例: 併發的Echo服務</h2>
|
||||
<p>TODO</p>
|
||||
<p>clock服務器每一個連接都會起一個goroutine。在本節中我們會創建一個echo服務器,這個服務在每個連接中會有多個goroutine。大多數echo服務僅僅會返迴他們讀取到的內容,就像下面這個簡單的handleConn函數所做的一樣:</p>
|
||||
<pre><code class="lang-go"><span class="hljs-keyword">func</span> handleConn(c net.Conn) {
|
||||
io.Copy(c, c) <span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> ignoring errors</span>
|
||||
c.Close()
|
||||
}
|
||||
</code></pre>
|
||||
<p>一個更有意思的echo服務應該模擬一個實際的echo的“迴響”,併且一開始要用大寫HELLO來表示“聲音很大”,之後經過一小段延遲返迴一個有所緩和的Hello,然後一個全小寫字母的hello表示聲音漸漸變小直至消失,像下面這個版本的handleConn(譯註:笑看作者腦洞大開):</p>
|
||||
<pre><code class="lang-go">gopl.io/ch8/reverb1
|
||||
<span class="hljs-keyword">func</span> echo(c net.Conn, shout <span class="hljs-typename">string</span>, delay time.Duration) {
|
||||
fmt.Fprintln(c, <span class="hljs-string">"\t"</span>, strings.ToUpper(shout))
|
||||
time.Sleep(delay)
|
||||
fmt.Fprintln(c, <span class="hljs-string">"\t"</span>, shout)
|
||||
time.Sleep(delay)
|
||||
fmt.Fprintln(c, <span class="hljs-string">"\t"</span>, strings.ToLower(shout))
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> handleConn(c net.Conn) {
|
||||
input := bufio.NewScanner(c)
|
||||
<span class="hljs-keyword">for</span> input.Scan() {
|
||||
echo(c, input.Text(), <span class="hljs-number">1</span>*time.Second)
|
||||
}
|
||||
<span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> ignoring potential errors from input.Err()</span>
|
||||
c.Close()
|
||||
}
|
||||
</code></pre>
|
||||
<p>我們需要陞級我們的客戶端程序,這樣它就可以發送終端的輸入到服務器,併把服務端的返迴輸出到終端上,這使我們有了使用併發的另一個好機會:</p>
|
||||
<pre><code class="lang-go">gopl.io/ch8/netcat2
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
conn, err := net.Dial(<span class="hljs-string">"tcp"</span>, <span class="hljs-string">"localhost:8000"</span>)
|
||||
<span class="hljs-keyword">if</span> err != <span class="hljs-constant">nil</span> {
|
||||
log.Fatal(err)
|
||||
}
|
||||
<span class="hljs-keyword">defer</span> conn.Close()
|
||||
<span class="hljs-keyword">go</span> mustCopy(os.Stdout, conn)
|
||||
mustCopy(conn, os.Stdin)
|
||||
}
|
||||
</code></pre>
|
||||
<p>當main goroutine從標準輸入流中讀取內容併將其發送給服務器時,另一個goroutine會讀取併打印服務端的響應。當main goroutine碰到輸入終止時,例如,用戶在終端中按了Control-D(^D),在windows上是Control-Z,這時程序就會被終止,盡管其它goroutine中還有進行中的任務。(在8.4.1中引入了channels後我們會明白如何讓程序等待兩邊都結束)。</p>
|
||||
<p>下面這個會話中,客戶端的輸入是左對齊的,服務端的響應會用縮進來區别顯示。
|
||||
客戶端會向服務器“喊三次話”:</p>
|
||||
<pre><code>$ go build gopl.io/ch8/reverb1
|
||||
$ ./reverb1 &
|
||||
$ go build gopl.io/ch8/netcat2
|
||||
$ ./netcat2
|
||||
Hello?
|
||||
HELLO?
|
||||
Hello?
|
||||
hello?
|
||||
Is there anybody there?
|
||||
IS THERE ANYBODY THERE?
|
||||
Yooo-hooo!
|
||||
Is there anybody there?
|
||||
is there anybody there?
|
||||
YOOO-HOOO!
|
||||
Yooo-hooo!
|
||||
yooo-hooo!
|
||||
^D
|
||||
$ killall reverb1
|
||||
</code></pre><p>註意客戶端的第三次shout在前一個shout處理完成之前一直沒有被處理,這貌似看起來不是特别“現實”。眞實世界里的迴響應該是會由三次shout的迴聲組合而成的。爲了模擬眞實世界的迴響,我們需要更多的goroutine來做這件事情。這樣我們就再一次地需要go這個關鍵詞了,這次我們用它來調用echo:</p>
|
||||
<pre><code class="lang-go">gopl.io/ch8/reverb2
|
||||
<span class="hljs-keyword">func</span> handleConn(c net.Conn) {
|
||||
input := bufio.NewScanner(c)
|
||||
<span class="hljs-keyword">for</span> input.Scan() {
|
||||
<span class="hljs-keyword">go</span> echo(c, input.Text(), <span class="hljs-number">1</span>*time.Second)
|
||||
}
|
||||
<span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> ignoring potential errors from input.Err()</span>
|
||||
c.Close()
|
||||
}
|
||||
</code></pre>
|
||||
<p>go後跟的函數的參數會在go語句自身執行時被求值;因此input.Text()會在main goroutine中被求值。
|
||||
現在迴響是併發併且會按時間來覆蓋掉其它響應了:</p>
|
||||
<pre><code>$ go build gopl.io/ch8/reverb2
|
||||
$ ./reverb2 &
|
||||
$ ./netcat2
|
||||
Is there anybody there?
|
||||
IS THERE ANYBODY THERE?
|
||||
Yooo-hooo!
|
||||
Is there anybody there?
|
||||
YOOO-HOOO!
|
||||
is there anybody there?
|
||||
Yooo-hooo!
|
||||
yooo-hooo!
|
||||
^D
|
||||
$ killall reverb2
|
||||
</code></pre><p>讓服務使用併發不隻是處理多個客戶端的請求,甚至在處理單個連接時也可能會用到,就像我們上面的兩個go關鍵詞的用法。然而在我們使用go關鍵詞的同時,需要慎重地考慮net.Conn中的方法在併發地調用時是否安全,事實上對於大多數類型來説也確實不安全。我們會在下一章中詳細地探討併發安全性。</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Channels | Go编程语言</title>
|
||||
<title>Channels | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.4" data-chapter-title="Channels" data-filepath="ch8/ch8-04.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.4" data-chapter-title="Channels" data-filepath="ch8/ch8-04.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>併行的循環 | Go编程语言</title>
|
||||
<title>併行的循環 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.5" data-chapter-title="併行的循環" data-filepath="ch8/ch8-05.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.5" data-chapter-title="併行的循環" data-filepath="ch8/ch8-05.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>示例: 併發的Web爬蟲 | Go编程语言</title>
|
||||
<title>示例: 併發的Web爬蟲 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.6" data-chapter-title="示例: 併發的Web爬蟲" data-filepath="ch8/ch8-06.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.6" data-chapter-title="示例: 併發的Web爬蟲" data-filepath="ch8/ch8-06.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
110
ch8/ch8-07.html
110
ch8/ch8-07.html
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>基於select的多路複用 | Go编程语言</title>
|
||||
<title>基於select的多路複用 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.7" data-chapter-title="基於select的多路複用" data-filepath="ch8/ch8-07.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.7" data-chapter-title="基於select的多路複用" data-filepath="ch8/ch8-07.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -2024,7 +2024,105 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="87-基於select的多路複用">8.7. 基於select的多路複用</h2>
|
||||
<p>TODO</p>
|
||||
<p>下面的程序會進行火箭發射的倒計時。time.Tick函數返迴一個channel,程序會週期性地像一個節拍器一樣向這個channel發送事件。每一個事件的值是一個時間戳,不過更有意思的是其傳送方式。</p>
|
||||
<pre><code class="lang-go">gopl.io/ch8/countdown1
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
fmt.Println(<span class="hljs-string">"Commencing countdown."</span>)
|
||||
tick := time.Tick(<span class="hljs-number">1</span> * time.Second)
|
||||
<span class="hljs-keyword">for</span> countdown := <span class="hljs-number">10</span>; countdown > <span class="hljs-number">0</span>; countdown-- {
|
||||
fmt.Println(countdown)
|
||||
j<-tick
|
||||
}
|
||||
launch()
|
||||
}
|
||||
</code></pre>
|
||||
<p>現在我們讓這個程序支持在倒計時中,用戶按下return鍵時直接中斷發射流程。首先,我們啟動一個goroutine,這個goroutine會嚐試從標準輸入中調入一個單獨的byte併且,如果成功了,會向名爲abort的channel發送一個值。</p>
|
||||
<pre><code class="lang-go">gopl.io/ch8/countdown2
|
||||
abort := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">struct</span>{})
|
||||
<span class="hljs-keyword">go</span> <span class="hljs-keyword">func</span>() {
|
||||
os.Stdin.Read(<span class="hljs-built_in">make</span>([]<span class="hljs-typename">byte</span>, <span class="hljs-number">1</span>)) <span class="hljs-comment">// read a single byte</span>
|
||||
abort <- <span class="hljs-keyword">struct</span>{}{}
|
||||
}()
|
||||
</code></pre>
|
||||
<p>現在每一次計數循環的迭代都需要等待兩個channel中的其中一個返迴事件了:ticker channel當一切正常時(就像NASA jorgon的"nominal",譯註:這梗估計我們是不懂了)或者異常時返迴的abort事件。我們無法做到從每一個channel中接收信息,如果我們這麽做的話,如果第一個channel中沒有事件發過來那麽程序就會立刻被阻塞,這樣我們就無法收到第二個channel中發過來的事件。這時候我們需要多路複用(multiplex)這些操作了,爲了能夠多路複用,我們使用了select語句。</p>
|
||||
<pre><code class="lang-go"><span class="hljs-keyword">select</span> {
|
||||
<span class="hljs-keyword">case</span> <-ch1:
|
||||
<span class="hljs-comment">// ...</span>
|
||||
<span class="hljs-keyword">case</span> x := <-ch2:
|
||||
<span class="hljs-comment">// ...use x...</span>
|
||||
<span class="hljs-keyword">case</span> ch3 <- y:
|
||||
<span class="hljs-comment">// ...</span>
|
||||
<span class="hljs-keyword">default</span>:
|
||||
<span class="hljs-comment">// ...</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>上面是select語句的一般形式。和switch語句稍微有點相似,也會有幾個case和最後的default選擇支。每一個case代表一個通信操作(在某個channel上進行發送或者接收)併且會包含一些語句組成的一個語句塊。一個接收表達式可能隻包含接收表達式自身(譯註:不把接收到的值賦值給變量什麽的),就像上面的第一個case,或者包含在一個簡短的變量聲明中,像第二個case里一樣;第二種形式讓你能夠引用接收到的值。</p>
|
||||
<p>select會等待case中有能夠執行的case時去執行。當條件滿足時,select才會去通信併執行case之後的語句;這時候其它通信是不會執行的。一個沒有任何case的select語句寫作select{},會永遠地等待下去。</p>
|
||||
<p>讓我們迴到我們的火箭發射程序。time.After函數會立卽返迴一個channel,併起一個新的goroutine在經過特定的時間後向該channel發送一個獨立的值。下面的select語句會會一直等待到兩個事件中的一個到達,無論是abort事件或者一個10秒經過的事件。如果10秒經過了還沒有abort事件進入,那麽火箭就會發射。</p>
|
||||
<pre><code class="lang-go"><span class="hljs-keyword">func</span> main() {
|
||||
<span class="hljs-comment">// ...create abort channel...</span>
|
||||
|
||||
fmt.Println(<span class="hljs-string">"Commencing countdown. Press return to abort."</span>)
|
||||
<span class="hljs-keyword">select</span> {
|
||||
<span class="hljs-keyword">case</span> <-time.After(<span class="hljs-number">10</span> * time.Second):
|
||||
<span class="hljs-comment">// Do nothing.</span>
|
||||
<span class="hljs-keyword">case</span> <-abort:
|
||||
fmt.Println(<span class="hljs-string">"Launch aborted!"</span>)
|
||||
<span class="hljs-keyword">return</span>
|
||||
}
|
||||
launch()
|
||||
}
|
||||
</code></pre>
|
||||
<p>下面這個例子更微秒。ch這個channel的buffer大小是1,所以會交替的爲空或爲滿,所以隻有一個case可以進行下去,無論i是奇數或者偶數,它都會打印0 2 4 6 8。</p>
|
||||
<pre><code class="lang-go">ch := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-typename">int</span>, <span class="hljs-number">1</span>)
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++ {
|
||||
<span class="hljs-keyword">select</span> {
|
||||
<span class="hljs-keyword">case</span> x := <-ch:
|
||||
fmt.Println(x) <span class="hljs-comment">// "0" "2" "4" "6" "8"</span>
|
||||
<span class="hljs-keyword">case</span> ch <- i:
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>如果多個case同時就緒時,select會隨機地選擇一個執行,這樣來保證每一個channel都有平等的被select的機會。增加前一個例子的buffer大小會使其輸出變得不確定,因爲當buffer旣不爲滿也不爲空時,select語句的執行情況就像是拋硬幣的行爲一樣是隨機的。</p>
|
||||
<p>下面讓我們的發射程序打印倒計時。這里的select語句會使每次循環迭代等待一秒來執行退出操作。</p>
|
||||
<pre><code class="lang-go">gopl.io/ch8/countdown3
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
<span class="hljs-comment">// ...create abort channel...</span>
|
||||
|
||||
fmt.Println(<span class="hljs-string">"Commencing countdown. Press return to abort."</span>)
|
||||
tick := time.Tick(<span class="hljs-number">1</span> * time.Second)
|
||||
<span class="hljs-keyword">for</span> countdown := <span class="hljs-number">10</span>; countdown > <span class="hljs-number">0</span>; countdown-- {
|
||||
fmt.Println(countdown)
|
||||
<span class="hljs-keyword">select</span> {
|
||||
<span class="hljs-keyword">case</span> <-tick:
|
||||
<span class="hljs-comment">// Do nothing.</span>
|
||||
<span class="hljs-keyword">case</span> <-abort:
|
||||
fmt.Println(<span class="hljs-string">"Launch aborted!"</span>)
|
||||
<span class="hljs-keyword">return</span>
|
||||
}
|
||||
}
|
||||
launch()
|
||||
}
|
||||
</code></pre>
|
||||
<p>time.Tick函數表現得好像它創建了一個在循環中調用time.Sleep的goroutine,每次被喚醒時發送一個事件。當countdown函數返迴時,它會停止從tick中接收事件,但是ticker這個goroutine還依然存活,繼續徒勞地嚐試從channel中發送值,然而這時候已經沒有其它的goroutine會從該channel中接收值了--這被稱爲goroutine洩露(§8.4.4)。</p>
|
||||
<p>Tick函數挺方便,但是隻有當程序整個生命週期都需要這個時間時我們使用它才比較合適。否則的話,我們應該使用下面的這種模式:</p>
|
||||
<pre><code class="lang-go">ticker := time.NewTicker(<span class="hljs-number">1</span> * time.Second)
|
||||
<-ticker.C <span class="hljs-comment">// receive from the ticker's channel</span>
|
||||
ticker.Stop() <span class="hljs-comment">// cause the ticker's goroutine to terminate</span>
|
||||
</code></pre>
|
||||
<p>有時候我們希望能夠從channel中發送或者接收值,併避免因爲發送或者接收導致的阻塞,尤其是當channel沒有準備好寫或者讀時。select語句就可以實現這樣的功能。select會有一個default來設置當其它的操作都不能夠馬上被處理時程序需要執行哪些邏輯。</p>
|
||||
<p>下面的select語句會在abort channel中有值時,從其中接收值;無值時什麽都不做。這是一個非阻塞的接收操作;反複地做這樣的操作叫做“輪詢channel”。</p>
|
||||
<pre><code class="lang-go"><span class="hljs-keyword">select</span> {
|
||||
<span class="hljs-keyword">case</span> <-abort:
|
||||
fmt.Printf(<span class="hljs-string">"Launch aborted!\n"</span>)
|
||||
<span class="hljs-keyword">return</span>
|
||||
<span class="hljs-keyword">default</span>:
|
||||
<span class="hljs-comment">// do nothing</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>channel的零值是nil。也許會讓你覺得比較奇怪,nil的channel有時候也是有一些用處的。因爲對一個nil的channel發送和接收操作會永遠阻塞,在select語句中操作nil的channel永遠都不會被select到。</p>
|
||||
<p>這使得我們可以用nil來激活或者禁用case,來達成處理其它輸入或輸出事件時超時和取消的邏輯。我們會在下一節中看到一個例子。</p>
|
||||
<p>練習8.8: 使用select來改造8.3節中的echo服務器,爲其增加超時,這樣服務器可以在客戶端10秒中沒有任何喊話時自動斷開連接。</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>示例: 併發的字典遍歷 | Go编程语言</title>
|
||||
<title>示例: 併發的字典遍歷 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.8" data-chapter-title="示例: 併發的字典遍歷" data-filepath="ch8/ch8-08.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.8" data-chapter-title="示例: 併發的字典遍歷" data-filepath="ch8/ch8-08.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>併發的退出 | Go编程语言</title>
|
||||
<title>併發的退出 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.9" data-chapter-title="併發的退出" data-filepath="ch8/ch8-09.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.9" data-chapter-title="併發的退出" data-filepath="ch8/ch8-09.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>示例: 聊天服務 | Go编程语言</title>
|
||||
<title>示例: 聊天服務 | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8.10" data-chapter-title="示例: 聊天服務" data-filepath="ch8/ch8-10.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8.10" data-chapter-title="示例: 聊天服務" data-filepath="ch8/ch8-10.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
10
ch8/ch8.html
10
ch8/ch8.html
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Goroutines和Channels | Go编程语言</title>
|
||||
<title>Goroutines和Channels | Go语言圣经</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="8" data-chapter-title="Goroutines和Channels" data-filepath="ch8/ch8.md" data-basepath=".." data-revision="Mon Dec 28 2015 16:03:52 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="8" data-chapter-title="Goroutines和Channels" data-filepath="ch8/ch8.md" data-basepath=".." data-revision="Thu Dec 31 2015 16:18:40 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -575,7 +575,7 @@
|
||||
|
||||
<b>4.2.</b>
|
||||
|
||||
切片
|
||||
Slice
|
||||
</a>
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
<b>4.3.</b>
|
||||
|
||||
字典
|
||||
Map
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2013,7 +2013,7 @@
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||||
<a href="../" >Go编程语言</a>
|
||||
<a href="../" >Go语言圣经</a>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user