W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
原文鏈接:https://gopl-zh.github.io/ch8/ch8-03.html
clock服務(wù)器每一個連接都會起一個goroutine。在本節(jié)中我們會創(chuàng)建一個echo服務(wù)器,這個服務(wù)在每個連接中會有多個goroutine。大多數(shù)echo服務(wù)僅僅會返回他們讀取到的內(nèi)容,就像下面這個簡單的handleConn函數(shù)所做的一樣:
func handleConn(c net.Conn) {
io.Copy(c, c) // NOTE: ignoring errors
c.Close()
}
一個更有意思的echo服務(wù)應(yīng)該模擬一個實際的echo的“回響”,并且一開始要用大寫HELLO來表示“聲音很大”,之后經(jīng)過一小段延遲返回一個有所緩和的Hello,然后一個全小寫字母的hello表示聲音漸漸變小直至消失,像下面這個版本的handleConn(譯注:笑看作者腦洞大開):
gopl.io/ch8/reverb1
func echo(c net.Conn, shout string, delay time.Duration) {
fmt.Fprintln(c, "\t", strings.ToUpper(shout))
time.Sleep(delay)
fmt.Fprintln(c, "\t", shout)
time.Sleep(delay)
fmt.Fprintln(c, "\t", strings.ToLower(shout))
}
func handleConn(c net.Conn) {
input := bufio.NewScanner(c)
for input.Scan() {
echo(c, input.Text(), 1*time.Second)
}
// NOTE: ignoring potential errors from input.Err()
c.Close()
}
我們需要升級我們的客戶端程序,這樣它就可以發(fā)送終端的輸入到服務(wù)器,并把服務(wù)端的返回輸出到終端上,這使我們有了使用并發(fā)的另一個好機(jī)會:
gopl.io/ch8/netcat2
func main() {
conn, err := net.Dial("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
go mustCopy(os.Stdout, conn)
mustCopy(conn, os.Stdin)
}
當(dāng)main goroutine從標(biāo)準(zhǔn)輸入流中讀取內(nèi)容并將其發(fā)送給服務(wù)器時,另一個goroutine會讀取并打印服務(wù)端的響應(yīng)。當(dāng)main goroutine碰到輸入終止時,例如,用戶在終端中按了Control-D(^D),在windows上是Control-Z,這時程序就會被終止,盡管其它goroutine中還有進(jìn)行中的任務(wù)。(在8.4.1中引入了channels后我們會明白如何讓程序等待兩邊都結(jié)束。)
下面這個會話中,客戶端的輸入是左對齊的,服務(wù)端的響應(yīng)會用縮進(jìn)來區(qū)別顯示。 客戶端會向服務(wù)器“喊三次話”:
$ 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
注意客戶端的第三次shout在前一個shout處理完成之前一直沒有被處理,這貌似看起來不是特別“現(xiàn)實”。真實世界里的回響應(yīng)該是會由三次shout的回聲組合而成的。為了模擬真實世界的回響,我們需要更多的goroutine來做這件事情。這樣我們就再一次地需要go這個關(guān)鍵詞了,這次我們用它來調(diào)用echo:
gopl.io/ch8/reverb2
func handleConn(c net.Conn) {
input := bufio.NewScanner(c)
for input.Scan() {
go echo(c, input.Text(), 1*time.Second)
}
// NOTE: ignoring potential errors from input.Err()
c.Close()
}
go后跟的函數(shù)的參數(shù)會在go語句自身執(zhí)行時被求值;因此input.Text()會在main goroutine中被求值。 現(xiàn)在回響是并發(fā)并且會按時間來覆蓋掉其它響應(yīng)了:
$ 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
讓服務(wù)使用并發(fā)不只是處理多個客戶端的請求,甚至在處理單個連接時也可能會用到,就像我們上面的兩個go關(guān)鍵詞的用法。然而在我們使用go關(guān)鍵詞的同時,需要慎重地考慮net.Conn中的方法在并發(fā)地調(diào)用時是否安全,事實上對于大多數(shù)類型來說也確實不安全。我們會在下一章中詳細(xì)地探討并發(fā)安全性。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: