99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

Go 語(yǔ)言 示例: 并發(fā)的Echo服務(wù)

2023-03-14 16:57 更新

原文鏈接:https://gopl-zh.github.io/ch8/ch8-03.html


8.3. 示例: 并發(fā)的Echo服務(wù)

clock服務(wù)器每一個(gè)連接都會(huì)起一個(gè)goroutine。在本節(jié)中我們會(huì)創(chuàng)建一個(gè)echo服務(wù)器,這個(gè)服務(wù)在每個(gè)連接中會(huì)有多個(gè)goroutine。大多數(shù)echo服務(wù)僅僅會(huì)返回他們讀取到的內(nèi)容,就像下面這個(gè)簡(jiǎn)單的handleConn函數(shù)所做的一樣:

func handleConn(c net.Conn) {
    io.Copy(c, c) // NOTE: ignoring errors
    c.Close()
}

一個(gè)更有意思的echo服務(wù)應(yīng)該模擬一個(gè)實(shí)際的echo的“回響”,并且一開(kāi)始要用大寫HELLO來(lái)表示“聲音很大”,之后經(jīng)過(guò)一小段延遲返回一個(gè)有所緩和的Hello,然后一個(gè)全小寫字母的hello表示聲音漸漸變小直至消失,像下面這個(gè)版本的handleConn(譯注:笑看作者腦洞大開(kāi)):

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()
}

我們需要升級(jí)我們的客戶端程序,這樣它就可以發(fā)送終端的輸入到服務(wù)器,并把服務(wù)端的返回輸出到終端上,這使我們有了使用并發(fā)的另一個(gè)好機(jī)會(huì):

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ù)器時(shí),另一個(gè)goroutine會(huì)讀取并打印服務(wù)端的響應(yīng)。當(dāng)main goroutine碰到輸入終止時(shí),例如,用戶在終端中按了Control-D(^D),在windows上是Control-Z,這時(shí)程序就會(huì)被終止,盡管其它goroutine中還有進(jìn)行中的任務(wù)。(在8.4.1中引入了channels后我們會(huì)明白如何讓程序等待兩邊都結(jié)束。)

下面這個(gè)會(huì)話中,客戶端的輸入是左對(duì)齊的,服務(wù)端的響應(yīng)會(huì)用縮進(jìn)來(lái)區(qū)別顯示。 客戶端會(huì)向服務(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在前一個(gè)shout處理完成之前一直沒(méi)有被處理,這貌似看起來(lái)不是特別“現(xiàn)實(shí)”。真實(shí)世界里的回響應(yīng)該是會(huì)由三次shout的回聲組合而成的。為了模擬真實(shí)世界的回響,我們需要更多的goroutine來(lái)做這件事情。這樣我們就再一次地需要go這個(gè)關(guān)鍵詞了,這次我們用它來(lái)調(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ù)會(huì)在go語(yǔ)句自身執(zhí)行時(shí)被求值;因此input.Text()會(huì)在main goroutine中被求值。 現(xiàn)在回響是并發(fā)并且會(huì)按時(shí)間來(lái)覆蓋掉其它響應(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ā)不只是處理多個(gè)客戶端的請(qǐng)求,甚至在處理單個(gè)連接時(shí)也可能會(huì)用到,就像我們上面的兩個(gè)go關(guān)鍵詞的用法。然而在我們使用go關(guān)鍵詞的同時(shí),需要慎重地考慮net.Conn中的方法在并發(fā)地調(diào)用時(shí)是否安全,事實(shí)上對(duì)于大多數(shù)類型來(lái)說(shuō)也確實(shí)不安全。我們會(huì)在下一章中詳細(xì)地探討并發(fā)安全性。



以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)