中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

個人怎么做旅游網站麗水網站seo

個人怎么做旅游網站,麗水網站seo,惠州網站制作,織夢怎么制作網站🏷?個人主頁:鼠鼠我捏,要死了捏的主頁 🏷?系列專欄:Golang全棧-專欄 🏷?個人學習筆記,若有缺誤,歡迎評論區(qū)指正 前些天發(fā)現了一個巨牛的人工智能學習網站,通俗易懂&…

🏷?個人主頁:鼠鼠我捏,要死了捏的主頁?

🏷?系列專欄:Golang全棧-專欄

🏷?個人學習筆記,若有缺誤,歡迎評論區(qū)指正?

前些天發(fā)現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到網站AI學習網站。

前言

當我們開發(fā)一個Web服務時,我們希望可以同時處理成千上萬的用戶請求,當我們有大量數據要計算時,我們希望可以同時開啟多個任務進行處理,隨著硬件性能的提升以及應用數據的增長,有越來越多的場景需要高并發(fā)處理,而高并發(fā)是Go的強項。

在這篇文章中,我們就一起來探究一下Go并發(fā)編程!

目錄

前言

并發(fā)與并行

并發(fā)

并行

Goroutines

什么是Goroutine

Goroutine的優(yōu)勢

啟動Goroutine

關閉Goroutine

Channel

什么是Channel

創(chuàng)建Channel

Channel操作

發(fā)送與接收

關閉

遍歷

無緩沖區(qū)Channel

有緩沖區(qū)Channel

Channel的串聯

單方向的channel

select:多路復用

Goroutine泄漏

小結


并發(fā)與并行

在談Go并發(fā)編程之前,我們需要對并發(fā)并行做一下區(qū)分。

并發(fā)

并發(fā)是指有多個任務處于運行狀態(tài),但無法確定到底任務的運行順序,比如某一時間,有一個雙核CPU,但有10個任務(線程),這些任務可能隨機被分配到相同或者不同的核心上去運行,但是其運行順序是不確定的。

并行

并行是指多個任務在某一個時刻同時運行,比如某一個時刻,一個雙核心的CPU,兩個核心同時都有一個任務在運行,那么就是說這兩個任務是并行的。

Goroutines

Goroutine是 Go語言的并發(fā)單元。

什么是Goroutine

Goroutine,中文稱為協程,我們可以把 Goroutine看作是一個輕量級的線程,而從代碼層面來看,Goroutine就是一個獨立運行的函數或方法。

Goroutine的優(yōu)勢

  1. 與線程相比,創(chuàng)建一個Goroutine的開銷要小得多,一個Goroutine初始化時只需要2KB,而一個線程則要2MB,所以Go程序可以大量創(chuàng)建Goroutine進行并發(fā)處理。
  2. 雖然協程初始化只有2KB,但卻可以根據需求動態(tài)擴展。
  3. Goroutine可以通過Channel互相通訊,而線程只能通過共享內存互相通訊。
  4. Goroutine由Go調度器進行調度,而線程則依賴系統的調度。

啟動Goroutine

要啟動一個Goroutine非常簡單,只要在函數或者方法前面加上 go關鍵字就可以了:

package main func Hello(){fmt.Println("hello")
}func main(){go Hello()//匿名函數go func(){fmt.Println("My Goroutine")}()
}

程序啟動后, main函數單獨運行在一個 Goroutine中,這個 Goroutine稱作 Main Goroutine,其他用go關鍵字啟動的Goroutine各自運行。

如果你在控制臺運行上面的程序,會發(fā)現在控制臺根據沒有任何輸出,這是為什么呢?

原因在于雖然所有的Goroutine是獨自運行的,但如果 Man Gorouine終止的話,那么所有 Goroutine 都會退出執(zhí)行。

上面的示例中,我們啟動的 Goroutine還沒運行,main函數就執(zhí)行結束了,因此整個程序就退出了。

package main import "time"func Hello(){fmt.Println("hello")
}func main(){go Hello()go func(){fmt.Println("My Goroutine")}()time.Sleep(time.Second)
}

上面的示例中,我們調用 time.Sleep()函數讓 Main Goroutine休眠而不退出,這時候其他的Goroutine就可以在 Main Goroutine退出前執(zhí)行。

關閉Goroutine

Go沒有提供關閉Goroutine的機制,一般來說要讓一個Goroutine停止有三種方式:

  • random?Goroutine執(zhí)行完成退出或者 return退出
  • main函數執(zhí)行完成,所有Goroutine自然就會終止
  • 直接終止整個程序的執(zhí)行(程序崩潰或調用os.Exit()),類似第2種方式。

Channel

Go并發(fā)編程的思想是:不要用共享內存來通訊,而是用通訊來共享內存。而這種通訊機制就是Channel。

什么是Channel

Channel是 Goroutine之間的通信機制,可以把 Channel理解為 Goroutine之間的一條管道,就像水可以從一個管道的一端流向另一端一樣,數據也可以通過 Channel從一個 Goroutine流向其他的一個 Goroutine,以實現 Goroutine之間的數據通訊。

創(chuàng)建Channel

創(chuàng)建 Channel類型的關鍵字是 chan,在 chan后面跟一個其他的數據類型,用于表示該 channel可發(fā)送什么類型的數據,比如一個可以發(fā)送整數的 Channel其定義是:

var ch chan int

Channel的默認值為nil,Channel必須實例化后才能使用,使用 make()函數實例化:

ch = make(chan int)ch1 := make(chan int)

Channel與map一樣是引用數據類型,在調用make()函數后,該Channel變量引用一塊底層數據結構,因此當把channel變量傳遞給函數時,調用者與被調用者引用的是同一塊數據結構。

Channel操作

Channel支持發(fā)送與接收兩種操作,無論是發(fā)送還是接收,都是用 <-運算符。

發(fā)送與接收

向Channel發(fā)送數據時,運算符 <-放在channel變量的右邊,運算符與Channel變量之間可以有空格:

ch <- x

接收Channel數據時,運算符 <-放在channel變量的左邊且之間不能有空格:

x <-ch
x <- ch //錯誤寫法

不接收channel的結果也是可以的:

<-ch

一個示例:

package mainimport "fmt"func main() {ch := make(chan int)go func(ch chan int) {ch <- 10}(ch)m := <-chfmt.Println(m)
}
關閉

使用內置 close可以關閉 Channel:

close(ch)

在關閉之后,如果再對該channel發(fā)送數據會導致panic錯誤:

close(ch)
ch <- x //panic

如果Channel中還有值未被接收,在關閉之后,還可以接收Channel里的值,如果沒有值,則返回一個0值。

package mainimport "fmt"func main() {ch := make(chan int)go func(ch chan int) {ch <- 10close(ch) //關閉}(ch)m := <-chn := <-ch//10,0fmt.Println(m, n)
}

在從Channel接收值的時候,也可以多接收一個布爾值,如果為true,表示可以接收到有效值,如果沒有值,則表示Channel被關閉且沒有值:

n,ok := <-ch

關閉一個已經關閉的Channel會導致panic,關閉一個nil值的Channel也會導致panic。

遍歷

Channel也可以用for...range語句來遍歷:

package mainimport ("fmt""time"
)func main() {ch := make(chan int)go func(ch chan int) {ch <- 10ch <- 20}(ch)go func(ch chan int) {for c := range ch {fmt.Println(c)}}(ch)time.Sleep(time.Second)
}

無緩沖區(qū)Channel

上面的示例中,調用make()函數時沒有指定第二個參數,這時創(chuàng)建的Channel稱為無緩沖區(qū)Channel。

對于使用無緩沖區(qū)進行通訊的兩個Goroutine來說,發(fā)送與阻塞都有可能會被阻塞,因此,本質使用無緩沖區(qū)的channel進行傳輸數據就是兩個Goroutine之間的一次數據同步,無緩沖區(qū)的Channel又被稱為同步Channel

package mainimport "fmt"func main() {ch := make(chan int)go func() {ch <- 10}()fmt.Println(<-ch)
}

有緩沖區(qū)Channel

調用 make()函數實例化 Channel時,也可以通過該函數的第二個參數指定 Channel的容量:

ch := make(chan int,2)

通過 cap()和 len()函數可以 Channel的長度:

cap(ch) //2
len(ch) //0
ch <- 10
len(ch) //1

對于帶有緩沖區(qū)的Channel來說,當Channel容量滿了,發(fā)送操作會阻塞,當Channel空的時候,接收操作會阻塞,只有當Channel未滿且有數據時,發(fā)送與接收才不會發(fā)生阻塞。

Channel的串聯

Channel是Goroutine之間溝通的管道,日常生活中,管道可以連接在一起,水可以從一條管道流向另一條管道,而Channel也是一樣的,數據可以從一個Channel流向另一個Channel。

package mainimport "fmt"func main() {ch1 := make(chan int)ch2 := make(chan int)go func() {for x := 0; x < 100; x++ {ch1 <- x}close(ch1)}()go func() {for {x, ok := <-ch1if !ok {break}ch2 <- x * x}close(ch2)}()for x := range ch2 {fmt.Println(x)}
}

單方向的channel

利用Channel進行通訊的大部分應用場景是一個Goroutine作為生產者,只負責發(fā)送數據,而另一個Goroutine作為消費者,接收數據。

對于生產者來說,不會對Channel執(zhí)行接收的操作,對于消費者來說不會對Channel執(zhí)行發(fā)送的操作

在聲明Channel變量將<-運算符放在 chan關鍵前面則該Channel只能執(zhí)行接收操作:

//只允許接收
var ch1 <-chan int

在聲明Channel變量將<-運算符放在 chan關鍵字后面可以則該Channel只能執(zhí)行發(fā)送操作:

//只允許發(fā)送
var ch2 chan<- int

像我們前面那正常聲明一個Channel變量,則允許對該Channel執(zhí)行發(fā)送和接收操作:

//可以發(fā)送和接收
var ch3 chan int

從一個只能發(fā)送數據的channel接收數據無法通過編譯:

var ch chan<- int
x := <-ch //報錯

向一個只有接收數據的channel發(fā)送數據無法通過編譯:

var ch <-chan int
ch <- 10 //報錯

對一個只有接收操作的 Channel執(zhí)行 close()也無法通過編譯:

var ch <-chan int
close(ch) //報錯

select:多路復用

前面的示例中,我們在一個 Goroutine中只向一個 Channel發(fā)送數據或者只從一個 Channel接收數據,因為如果同時向兩個Channel接收或發(fā)送數據時,如果第一個Channel沒有事件響應,程序會一直阻塞:

package mainimport ("fmt""time"
)func main() {ch1 := make(chan int)ch2 := make(chan int)go func(ch1 chan int, ch2 chan int) {fmt.Println("向ch1發(fā)送數據前")<-ch1fmt.Println("從ch2接收數據前")ch2 <- 1}(ch1, ch2)time.Sleep(1 * time.Second)
}

但很多場景下,我們需要在一個Goroutine中根據不同的Channel執(zhí)行不同的操作:比如一個啟動的Web服務器,在一個Goroutine中一邊處理請求,一邊監(jiān)聽信號量。要怎么做呢?

答案是:使用select語句,即多路復用,select語法類似switch語句,select語句塊中可以包含多個case分支和一個default分支,每個case分支表示一個向Channel發(fā)送或接收的操作,select語句會選擇可以執(zhí)行的case分支來執(zhí)行,如果沒有,則執(zhí)行default分支:

select {
case <-ch1:// do something
case x := <-ch2:// do somthing with x
case ch3 <- y:// do something
default:// dosomthing
}

下面我們通過一個案例來了解如何使用select語句,在這個例子中,我們模擬啟動一個Web服務器處理來自用戶的請求,而在處理請求的同時,還要可以根據接收的信息及時停止服務,我們在開啟單獨的一個Goroutine模擬向我們的Web發(fā)送停止信號:

package mainimport ("fmt""time"
)func main() {s := make(chan struct{})go func(s chan struct{}) {time.Sleep(time.Microsecond * 100)s <- struct{}{}}(s)MyWebServer(s)fmt.Println("服務已停止...")
}func MyWebServer(stop chan struct{}) {for {select {case <-stop:fmt.Println("服務器接收到停止信號")returndefault:}//模擬處理請求go HandleQuery()}
}func HandleQuery() {fmt.Println("處理請求...")
}

Goroutine泄漏

一個 Goroutine 由于從Channel接收或向 Channel 發(fā)送數據一直被阻塞,一直無法往下執(zhí)行時,這種情況稱為 Goroutine泄漏:

package mainimport "time"func main() {ch := make(chan int)go func() {ch <- 10}()time.Sleep(time.Second * 2)
}

Goroutine執(zhí)行完成退出后,由Go內存回收機制進行回收,但是發(fā)生內存泄漏的Goroutine并不會被回收,因此要避免發(fā)生這種情況。

總結

Go在語言層面支持并發(fā)編程,只需要在函數或者方法前加上go關鍵字便可以啟動一個Goroutine,而Channel作為Goroutine之間的通訊管道,可以非常方便Goroutine之間的數據通訊。

http://www.risenshineclean.com/news/63416.html

相關文章:

  • 怎么用數據庫做動態(tài)網站最近國際新聞大事
  • 鄭州旅游網站搭建網站流量分析
  • 食品營銷型網站建設全能搜
  • 天河移動網站建設新聞頭條今日新聞
  • 江蘇城鄉(xiāng)建設廳官方網站找關鍵詞的三種方法
  • 網站建設開發(fā)文檔湖北網絡營銷網站
  • 天津企業(yè)網站制作公司網絡推廣公司
  • 專注高密做網站哪家強滄州seo推廣
  • 公司做網站要花多少錢怎么宣傳網站
  • iis5.1發(fā)布網站建設一個網站的具體步驟
  • 國外財經網站是怎么做的天津短視頻seo
  • wordpress 子網站重命名微信指數
  • 購物平臺有哪些比較火北京百度推廣優(yōu)化排名
  • 三門峽市建設局官方網站seo技術培訓山東
  • 今日疫情新聞發(fā)布會直播手機游戲性能優(yōu)化軟件
  • 動態(tài)網站中如何做項目欄六盤水seo
  • 重慶婦科醫(yī)院免費咨詢武漢谷歌seo
  • 江蘇網站開發(fā)百度人工服務電話
  • 萬網主機 建網站推廣網站排名優(yōu)化seo教程
  • 深圳品牌醫(yī)療網站建設百度趨勢搜索
  • 福州網站建設兼職網絡營銷專業(yè)介紹
  • 公司的國外網站怎么建新品怎么刷關鍵詞
  • 哈爾濱建設網站官網網站在線客服系統 免費
  • 陜西西安最新疫情廣州seo效果
  • 外貿汽車網站有哪些互聯網營銷模式有哪些
  • 渝中網站建設成都網絡營銷推廣公司
  • 中國流量最大的網站排行百度推廣開戶流程
  • 電子商務網站建設的核心是免費收錄網站提交
  • 可以做問卷掙錢的網站怎么在百度發(fā)布免費廣告
  • 為什么搜索不到剛做的網站如何做網絡推廣人員