SlideShare una empresa de Scribd logo
1 de 65
Golang 入門初體驗
學習主題
• 社群成立目的簡介
• 自我介紹與哈啦
• 功力複習
• 程式實作(Golang)
• 問題與交流
個人簡介
諸葛魔斌
工作室:諸葛魔斌科技創作室
學歷:高應大---工管系(非資訊科系)
E-Mail:chugermobin@gmail.com
官方網站:http://twcts.com
Facebook:https://goo.gl/volM7Z
粉絲團 :https://goo.gl/LI08wh
社群 :https://goo.gl/kjCsz1
Line (id) :http://goo.gl/ayGW7d
Line@ :http://goo.gl/pQHjWH
Line Bot :http://goo.gl/ljdxfV
Play商店:http://goo.gl/CkVdsd
App Store:http://apple.co/1Qehd64
專長:VB(VBA)、C#、Java(Android)、Swift(iOS)、PHP、Python、Conrona、
Golang、Unity、MySQL、FreeBSD、Server架設、CAD 、 ……
楊政斌
學習程式的歷程
學生時期:打電動,沒有日夜的界限
二專畢業:初次接觸 dBase、Lotus  使用 Clipper 做經銷存、應收付帳系統
工作階段1:接觸 Office,開始使用Excel(Lotus)
工作階段2:品保工作,自學圖表、函數、VBA,做出自動化品管系統
興趣展開:自學VB,製作ERP系統,接觸Linux、FreeBSD,自學架設Server
 諸葛魔斌誕生
大學時期:半自學 Android App(Java)、C#、iOS App(Swift)
工作轉變:成立諸葛魔斌科技創作室,接案學習,救國團電腦資訊講師
實績:
Golang 入門初體驗
Go,又稱golang,是Google開發的一種靜態強型別、編譯型,並發型,並具有垃圾回收功能的程
式語言。
羅伯特·格瑞史莫,羅勃·派克(Rob Pike)及肯·湯普遜於2007年9月開始設計Go語言,稍後Ian
Lance Taylor, Russ Cox加入專案中。Go語言是基於Inferno作業系統所開發的。Go語言於2009
年11月正式宣布推出,成為開放原始碼專案,並在Linux及Mac OS X平台上進行了實現,後追加
Windows系統下的實作。
Go語言的語法接近C語言,但是對於變數的聲明是不同的,其他語法不同之處是For迴圈和if判斷語
句不需要用小括弧括起來。Go語言支援垃圾回收功能。Go語言的並列模型是以東尼·霍爾的交談循
序程式(CSP)為基礎,採取類似模型的其他語言套件括Occam和Limbo,但它也具有Pi運算的特
徵,比如通道傳輸。
與C++相比,Go語言並不包括如例外處理、繼承、泛型、斷言、虛擬函式等功能,但增加了slice型、
並行、管道、垃圾回收、介面(interface)等特性的語言級支援。當然,Google對於泛型的態度
還是很開放的,但在該語言的常見問題列表中,對於斷言的存在,則持負面態度,同時也為自己不
提供型別繼承來辯護。不同於Java,Go語言內嵌了關聯陣列(也稱為雜湊表(hashes)或字典
(dictionaries)),就像字串類型一樣。
Golang 入門初體驗
當前有兩個Go語言的編譯器的分支。官方編譯器gc和gccgo。官方編譯器在初期使用C寫成,後用go
重寫從而實作自舉。Gccgo是一個使用標準GCC作為後端的Go編譯器。
官方編譯器支援跨平台編譯(但不支援CGO),允許將源碼編譯為可在目標系統、架構上執行的二進
位檔案。
Go 在2007年9月開始為 google 內部員工的 20% 自由時間的實驗項目, 目的為改善公司內部的開發速
度. 隔了一年受到 google 公司的重視和支持, 2009年11 月對外發佈第一版本. 過去 google 常用的語
言有 c , java , python來開發他們的服務. 但是這些語言是在創造的時候的硬體環境, 和現在有很大的
不同. 而 Golang 在設計的時候就考慮了這些架構, 所以在開發上和過去的語言比較起來有很大的優勢.
Go的關鍵字不多(目前約25個 c 37個,c++ 84個而且還在增加中), 學習上很容易上手, 再加上有不少和
c 的關鍵字重複, 所以如果你原本就是寫c/c++的人, 在轉換上會相對其他語言容易.
平均下來效能是輸c, 可是贏其他語言如 ruby(ror), php, java, python等語言. 主要原因的先天優勢是,
他語言架構設計非常單純, 並不像是如物件導向語言這麼的大. 再來是他不是直譯語言. 光是這兩點優
勢, 讓他有更好的體質去有較好的執行效率. 已經有很多案例, 在開發伺服器的軟體時, 因為效能問題而
改換 go 去寫, 結果讓他們減少了伺服器的數量就可以達到原本的效能, 增加了服務的效率也省下了硬
體成本.
Golang 入門初體驗
goroutine
這是Go的最大特色之一, thread 的使用是非常消耗系統資源的, 而且當你使用越來越多時管理上也越
困難. 而 goroutine 有輕巧低消耗資源的特性, 而這優點在於系統資源的消耗也會比較少.
可以使用 c library
他可以使用 c library, 解決新語言在 library 上的不足. 不過基本上 go 本身的 lib 已經很豐富了.
Unicode slice map 都有支援.
目前越來越多公司用 go 來寫他們網站後端的系統, 過去 google 在寫他的服務大多使用 c + python,
python 是個很簡潔的語言在建構服務是非常快的, c 是用來解決效能上的問題, 現在內部也都慢慢轉成
go 來寫. 在2014年TIOBE四月程式語言排名已經到第30名, 2013基本上都是在50名以外, 而且我相信
這名次會持續在進步.
第一個 go 程式
package main
import "fmt“
func main () {
fmt.Println("Hello , World!")
}
Golang 入門初體驗
Go 安裝
http://golang.org/dl/
Windows:
安裝好 GO 後, 還需要 GCC 編譯環境, 因為 Mac 的 Xcode 本身就有 GCC, windows 沒有, 所以
選擇了 mingw 這個輕量型的 GCC
http://blog.jex.tw/blog/2013/12/17/windows-install-gcc-compiler-mingw/
設定 GOPATH, 這是放一些你自己或 go get from github 存放的地方
1. 在 c:Go 下建立 mygo 資料夾, 並且在 mygo 下建立三個資料夾 src, pkg, bin
2. 設定環境變數
GOROOT : C:Go GOPATH : C:Gomygo PATH :
在最後面加上 ;%GOROOT%bin;%GOPATH%bin;C:Program Files (x86)Gitbin
除了加上 GOROOTbin、GOPATHbin, 也可視需求加上 git bin 的路徑,重新啟動 cmd 使變數
生效
Golang 入門初體驗
Go 執行
https://golang.org/cmd/go/
go run
要撰寫第一個 Hello, World 程式,你可以建立一個 main.go,在當中撰寫以下的內容:
package main
import "fmt"
func main() {
fmt.Println("Hello, World")
fmt.Println("哈囉!世界!")
}
Golang 入門初體驗
Go 執行
每個 .go 原始碼,都必須從 package 定義開始,而對於包括程式進入點 main 函式的 .go 原始碼,
必須是在 package main 之中,為了要能輸出訊息,這邊使用了 fmt 套件(package)之中的
Println 函式,開頭的大寫 P 表示這是個公開的函式,可以在套件之外進行呼叫。
Go 的創建者之一也是 UTF-8 的創建者,因此,Go 可以直接處理多國語言,只要你確定編輯器
編碼為 UTF-8 就可以了,如果你使用 vim,可以在 vim 的命令模式下輸入 :set encoding=utf-8,
或者是在 .vimrc 之中增加一行 set encoding=utf-8。
Go 可以用直譯的方式來執行程式,第一個 Hello, World 程式就是這麼做的,執行 go run 指定
你的原始碼檔名就可以了:
$ go run main.go
Hello, World
哈囉!世界!
package 與 GOPATH
Golang 入門初體驗
Go 執行
那麼,一開始的 package 是怎麼回事?試著先來建立一個 hello.go:
package hello
import "fmt"
func HelloWorld() {
fmt.Println("Hello, World")
}
Golang 入門初體驗
Go 執行
記得,package 中定義的函式,名稱必須是以大寫開頭,其他套件外的程式,才能進行呼叫,若
函式名稱是小寫,那麼會是套件中才可以使用的函式。
接著,原本的 main.go 修改為:
package main
import "hello"
func main() {
hello.HelloWorld()
}
Golang 入門初體驗
Go 執行
現在顯然地,main.go 中要用到方才建立的 hello 套件中的 HelloWorld 函式,這時 package 的
設定就會發揮一下效用,你得將 hello.go 移到 src/hello 目錄之中,也就是目錄名稱必須符合
package 設定之名稱。
而 src/hello 的位置,必須是在 GOROOT 底下,或者是 GOPATH 底下,當 Go 需要某個某個套
件中的元素時,會分別到這兩個環境變數的目錄之中,查看是否有相應於套件的原始碼存在。
為了方便,通常會設定 GOPATH,例如,指向目前的工作目錄:
export GOPATH=~workspacego
雖然目前 GOPATH 中只一個目錄,不過 GOPATH 中可以設定數個目錄
Golang 入門初體驗
Go 執行
go build
這個命令主要用於測試編譯。在包的編譯過程中,在必要情況下,還可以同時編譯與之關聯的包。
-普通包:執行完go build ,不會產生任何檔,如果需要在$GOPATH/pkg下生成相應檔,則要
執行go install.
-main 包:執行完go build,會在目前的目錄下生成一個可執行檔,如果需要在$GOPATH/bin下生成
對應檔,需要執行go install 或使用 go build -o outputpath/
如果只想編譯某個檔,只需在在後面加上檔案名即可,例如:go build hello.go
非main包在預設情況下編譯輸出的是package名,main包是第一個原始檔案的檔包,也還可以指定編
譯輸出的檔案名,例如,go build -o xialingsc.exe
Golang 入門初體驗
Go 執行
go build
go build 會忽略目錄下以"_"或"."開頭的go文件
如果原始程式碼針對不同的作業系統需要不同的處理,那麼可以根據不同的作業系統尾碼來命名檔。
例如,readfile_linux.go,readfile_drawin.go,readfile_windows.go.go build 會選擇性編譯
檔,Linux系統只編譯readfile_linux.go,其他文件則被忽略。
Golang 入門初體驗
Go 執行
go build
如果想編譯原始碼為可執行檔,那麼可以使用 go build,例如,直接 go build main.go,就會在
執行指令的目錄下,產生一個名稱為 main 的可執行檔,可執行檔的名稱是來自己指定的原始碼
檔案主檔名,執行產生出來的可執行檔就會顯示 Hello, World。
你也可以建立一個 bin 目錄,然後執行 go build -o bin/main main.go,這樣產生出來的可執行
檔,就會被放在 bin 底下,如果想將原始碼全部放在 src 底下管理,那麼就將 main.go 放到
src/main 底下,然後執行 go build -o bin/main src/main/main.go。
go install
每次使用 go build,都是從原始碼編譯為可執行檔,這比較沒有效率,如果想要編譯時更有效率
一些,可以使用 go install,例如,在目前既有的目錄與原始碼架構之下,執行 go install main
Golang 入門初體驗
Go 執行
go build
~go
|~bin/
| |-main
|~pkg/
| `~linux_arm/
| `-hello.a
|~src/
| |~hello/
| | `-hello.go
| |~main/
| | `-main.go
go install packageName 表示要安裝指定名稱的套件,如果是 main 套件,那麼會在 bin 中產生
可執行檔,如果是公用套件,那麼會在 pkg 目錄的 $GOOS_$GOARCH 目錄中產生 .a 檔案
Golang 入門初體驗
Go 執行
go build
可以使用 go env 來查看 Go 使用到的環境變數,例如:
$ go env
GOARCH="arm"
GOBIN=""
GOEXE=""
GOHOSTARCH="arm"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/root/workspace/go"
GORACE=""
GOROOT="/opt/go"
GOTOOLDIR="/opt/go/pkg/tool/linux_arm"
GO15VENDOREXPERIMENT=""
CC="gcc"
GOGCCFLAGS="-fPIC -marm -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
Golang 入門初體驗
Go 執行
go build
.a 檔案是編譯過後的套件,因此,你看到的 hello.a,就是 hello.go 編譯之後的結果,如果編譯
時需要某個套件,而對應的 .a 檔案存在,且原始碼自上次編譯後未曾經過修改,那麼就會直接使
用 .a 檔案,而不是從原始碼開始編譯起。
go clean
用來移除當前源碼包裡編譯生成的檔,這些檔包括,_obj(舊的objects目錄,Makefiles遺留),
_test(舊的test目錄),_testmain.go(舊的gotest文件),test.out、build.out(舊的test記錄)
*.[568ao] object文件,DIR(.exe)(由go build產生),DIR.test(.ext)(由go test -c產生),
MAINFILE(.exe) (由go build MAINFILE.go產生)
該命令最大的作用,清除編譯文件後,上傳git,保持源碼清潔。
Golang 入門初體驗
Go 執行
os.Args
那麼,如果想在執行 Go 程式時使用命令列引數呢?可以使用 os 套件的 Args,例如,寫一個
main.go:
package main
import "os"
import "fmt"
func main() {
fmt.Printf("Command: %sn", os.Args[0])
fmt.Printf("Hello, %sn", os.Args[1])
}
Golang 入門初體驗
Go 執行
os.Args 是個陣列,索引從 0 開始,索引 0 會是編譯後的可執行檔名稱,索引 1 開始會是你提供
的引數,例如,在執行過 go build 或 go install 之後,如下直接執行編譯出來的執行檔,會產生
的訊息是…
$ ./bin/main Justin
Command: ./bin/main
Hello, Justin
go doc
Golang 入門初體驗
Go 執行
fmt 的 Printf,就像是 C 的 printf,可用的格式控制字元可參考 Package fmt 的說明。實際上,
Go 本身附帶了說明文件,可以執行 go doc <pkg> <sym>[.<method>] 來查詢說明。例如:
$ go doc fmt.Printf
func Printf(format string, a ...interface{}) (n int, err error)
Printf formats according to a format specifier and writes to standard
output. It returns the number of bytes written and any write error
encountered.
Golang 入門初體驗
Go 執行
go fmt
幫助格式化寫好的代碼檔,讓寫代碼時不關心格式,寫完後,輕鬆執行go fmt 檔案名.go就好
提高效率。更多的時候可以採用gofmt,同時增加-w的參數,否則格式化結果不會寫入檔,例如:
gofmt -w src 來格式整個項目。
go get
動態獲取遠端代碼。這個代碼內部分為兩部分,一是下載源碼包,另一步是執行go install
為了讓go get正常使用,需保證安裝了合適的源碼管理工具,並將這些命令加入到PATH中。
可通過go help remote 瞭解更多。
go test
執行這個命令會自動讀取源碼目錄下名為*_test.go檔,生成並運行測試用的可執行檔。
預設情況下不需要任何參數,也可帶上參數,具體可參見go help testflag
Golang 入門初體驗
Go 執行
go doc
如何查看相應的package文檔呢?
如果是builtin包,可以執行go doc builtin;如果是http包,執行go doc net/http;
查看某個包裡面的函數,類似執行 godoc fmt Println,還可以查看相應代碼
godoc -src fmt Println
很棒的一點是,可以在終端執行godoc -http=:埠號,例如godoc -http=:8080 ,就可以在
流覽器中敲入127.0.0.1:8080進行文檔內容的查看。
其他命令
go fix 用來修復以前老版本的代碼到新版本
go version 查看go當前的版本
go env 查看當前go的環境變數
go list 列出當前全部安裝的package
go run 編譯並運行go語言程式
Golang 入門初體驗
Go IDEs
IDEs 有以下幾種,使用文字編輯器亦可完成程式編輯,再至Command Line執行編譯
Lite IDE
GoSublime
Visual Studio Code
Goclipse
VIM / VIM-go
Golang 入門初體驗
Go 語法 (參考 https://polor10101.gitbooks.io/golang_note/content/about_golang.html)
variable 變數
雖然號稱和 c 類似, 不過 go 在變數的命名上有很大的不同, 他是以 type 放後面為原則
以下表示宣告一個變數 x 且他是整數型態.
var x int
如果要給他初始值, 有以下幾種方式
給予初始值
var x int = 10
var y = 20
var z int
z = 30
k := 40
常數
const PI = 3.1415
const NAME = "Nelson"
常數不需要給定 type, 只要直接給予值即可.
而且不能用 ':=' 的方式給予初始值.
你可以發現每行的結尾少了分號 ';', 是的 go 省略分號, 只要斷行來分就好.
Golang 入門初體驗
Go 語法
函式
函式的宣告方式也和 c 不同
func add( a int , b int){
c := a + b
}
如果要回傳東西
func add( a int , b int) int{
c := a + b
return c
}
但是還是維持 type 在後面的原則
在此在大括號的位置也有規定, 如例子所示
Golang 入門初體驗
Go 語法
函式
你也可以
func add( a int , b int) int{ }
但是不可以採用對齊的方式
func add( a int , b int) int
{
}
從以上例子來看, 會發現 go 在程式的風格上有強制規定, 不符合規定會有 error
Golang 入門初體驗
Go 語法
函式
有幾點初學的時候有點不習慣
每行 code 不需要分號 ;
大括號的排版方式
import 某個 lib 或是宣告某變數但是實際卻沒有使用
宣告改成這個方式, 官方是說可以增加閱讀性. why? 這部份在其他章節會有描述
另外可以用變數直接指向 function
func add(a int,b int) int{
return a+b
}
Golang 入門初體驗
Go 語法
關於語法
go 在語法中做了改變, 官方的說法是, 改這樣的原因是因為這樣比較好閱讀. 接著來比較 c 和 go 的語法
以宣告 variable 來看
int add; //c
var add int //go
go 還多一個 var, 似乎也沒有比較方便
以 function 來看
int add(int a, intb); //c
func add(a int, b int)int //go
也還好, 不過比較起來 go 比較容易分辨出是 variable 還是 function, 但是差距也沒有很大, 而且 go 還需要多打
字.
Golang 入門初體驗
Go 語法
關於語法
如果宣告一個 function pointer 然後輸入一個 function pointer 變數
int (*fp)(int (*ff)(int x, int y), int b) //c
f func(func(int,int) int, int) int //go
c 已經有點讓人混亂了, 且不好閱讀.
go 這樣是不是有比較清楚?
個人是覺得有, 還很明顯.
再加個回傳 function pointer 的宣告比較.
int (*(*fp)(int (*)(int, int), int))(int, int) //c
f func(func(int,int) int, int) func(int, int) int //go
結論 : 真的有差.
f := add
f(10,20)
Golang 入門初體驗
Go 語法
loop 迴圈
以 c 來說迴圈有 for , while , do while 三個關鍵字. 在 go 裡面只有一個 for 來達到全部
以 for 迴圈來說 c 為
int i = 0;
int sum = 0;
for( i = 0 ; i < 10 ; ++i )
{
sum += i;
}
以下為 go 的 for 迴圈範例
sum := 0
for i := 0 ; i < 10 ; ++i {
sum += i
}
從範例中可以看到 "( )" 省略了, 再來兩個中夸號並不是對齊的
Golang 入門初體驗
Go 語法
loop 迴圈
c 的 do while 迴圈
int i = 0;
do{
i += 1
}while( i < 10 );
go 中為
i := 0
for i < 100 {
i += 1
}
c 的無限 while 迴圈
while(1)
{
}
go 的
for {
}
以上為 go 和 c 的迴圈使用比較. 從中可以了解一些語法上
的差別
Golang 入門初體驗
Go 語法
if switch
和 c 不同的是, if 不需要小括號, 另外大括號必須要有, 並且強制是範例的排版方式, 否則會有 error
if a > 0 {
fmt.Println(a)
}
個人是習慣對齊的方法, 不過這樣的強制規定可以讓多人開發專案的程式碼有一致性, 這也是個好處.
switch 也是同樣的規定, 並且不需要加上 'break'
如以下所示
switch i {
case 1 : fmt.Println(1)
case 2 : fmt.Println(2)
default : fmt.Println("default")
}
Golang 入門初體驗
Go 語法
Array
array 的宣告
var a [5]int //宣告一個大小5的 int array
var b []int //宣告空的 int array
var c = []int{1,2,3,4,5}//宣告一個大小5的 int array, 並給初始值
如果要列印 array 裡面的值, 你可以使用 range 知道 array 目前的 index
import "fmt"
func main() {
var a = [4]int {1,2,3,4}
for i := range a {
fmt.Println(a[i])
}
}
Golang 入門初體驗
Go 語法
Array
初始話也可以改成
var a = [4]int {
1,
2,
3,
4,
}
其中 4 的後面記得要有逗號 ','
Golang 入門初體驗
Go 語法
Slice
相對於 array, slice 提供了彈性, 不需要指定大小
是由三個元件組成
ptr
len
cap
其中 prt 是指向一個 array 的指標, 如圖所示
Golang 入門初體驗
Go 語法
Slice
len 為實際資料長度, cap 表示容量
宣告的方式為
a := []int
此時的 len , cap 都為 0
你可以用 make 來宣告變數並指定 len 和 cap 的值
a := make([]int,5,10)
其中 5 為len, 10 為 cap
Golang 入門初體驗
Go 語法
Slice
也可以不指定 cap 寫成
a := make([]int,5)
這時 len 為 5 , cap 為 5
另外給定初始值的宣告
var a = []int {1,2,3,4,5}
如果要一個變數指向 a
b := a[2:4]
c := a[:]
Golang 入門初體驗
Go 語法
Slice
其中
b 為 3 , 4.
a[2:4] 的 2 表示指向 a index = 2 的位置, 4 表示為結尾在 index = 4(不包含), 所以則 length 為 2, 另外由於
array 是連續的, 所以 cap = 3
c 為 1,2,3,4,5
[:] 表示 [0:len(a)], 第一個值如果沒寫則為 0, 第二個沒寫的為 len(a) = 5
Golang 入門初體驗
Go 語法
Slice
所以可以得知
a[:3] 和 a[1:] 個別為
1,2,3 //a[:3]
2,3,4,5 //a[1:]
另外要特別注意的是,
b := a[1:3]
並不是 a copy 值給 b, 而是將 b 的指標指向 a ( index 2 ) 的位置
所以這表示如果你改了 b 的值, a 的也會一起改變, 因為他們共用同一個 array.
如果你要兩者是獨立的, 可以使用 copy 的方法
copy(b,c)
Golang 入門初體驗
Go 語法
Slice
這是把 c 的前兩個的值, copy 到 b 中. 為什麼只 copy c 的前兩個?因為 b 的大小只有二, 以小的為主
copy(c,b)
則表示將 b 的值, copy 覆蓋 c 的前兩個值.
另外可以用 append 來增加他的大小
如下所示
import "fmt"
func main(){
var a[]int
a = append(a,1)
a = append(a,2)
for i := range a {
fmt.Println(a[i])
}
}
Golang 入門初體驗
Go 語法
Map
建立一個 map 可以用以下兩種方式
m := make(map[string]int)
m := map[string]int{}
定義 age = 16
m["age"] = 16
回傳值, 和 map 是否存在
value , ok := m["age"]
如果是不存在的 key , value = 0 , ok = false
value , ok := m["height"]
Golang 入門初體驗
Go 語法
Map
利用 rage 取得 map 中所有的 key 和 value, 並列印
for key, value := range m {
fmt.Println("Key:", key, "Value:", value)
}
如果要一次宣告多個值, 可以用以下方式
person := map[string]int{
"age" : 16,
"height" : 180,
"weight" : 6,
}
https://play.golang.org/p/rPpLGhc9lE
Golang 入門初體驗
Go 語法
Goroutine
在講goroutine之前, 必須先了解 concurrency 和 parllelism的不同
concurrency (併發) vs parallelism (並行)
併發 concurrency 是將 process 切割成多個可執行單位(coroutine), 如果有多個 process 時則在 coroutine 中
交互執行, 這樣不會因為某一個 process 執行太久造成其他 process 無法處理, 會讓你有多工的感覺. 但這並不
會增加執行效率. 總執行時間是一樣的, 如圖一所示. 另外和 thread 不同的是, thread 是屬於 os 層面上的, 且
thread 非常消耗系統資源.
Golang 入門初體驗
Go 語法
Goroutine
Golang 入門初體驗
Go 語法
Goroutine
並行 parallelism 是多個 process 由多個 cpu 去執行, 可以增加執行的效率, 縮短總執行的時間. 如圖二所示
Golang 入門初體驗
Go 語法
Goroutine
go 用 goroutine 實現了 concurrency. 使用者只要設定最大的 thread 數量, 和系統是多少CPU, run-time 就會
幫你處理好剩下的 thread 管理, 但為什麼 gorountine 可以提供較好的效能? (以下為個人心得可能有錯)
Golang 入門初體驗
Go 語法
Goroutine
第一. 在創造 goroutine 的資源消耗是很小的, 因為 goroutine 只是一個 function 的入口. 只要很小的 stack 去
記錄即可.
第二. thread 上的管理, 當某個 goroutine 被 block 住, 處理此 goroutine 的 thread 就耗在這上, 此時 run-time
會將其他的 goroutine 轉給此 thread 去執行, 這樣 thread 就不會因為執行某些被 block 的任務則消耗在那邊.
有效的使用 thread.
第三. thread 最多不會超過 $GOMAXPROCS(使用者設定的), 可以確保 thread 不會失控的增加.
綜合以上三點, goroutine 其實就是避免 thread 的不當增加, 有效的使用目前的 thread , 這樣系統資源的消耗就
少了. 不會因為系統的資源不夠造成整體效能的降低.
coroutine 資料一
coroutine 資料二
thread 資料
goroutine 資料一
goroutine 資料二
goroutine 資料三
Golang 入門初體驗
Go 語法
goroutine - channels
Don't communicate by sharing memory; share memory by communicating.
不同於過去的 muliti thread 的程式開發, 常使用共用變數去做資訊傳遞 (communicate by sharing memory).
goroutine 彼此的溝通方式是使用 channel (share memory by communicating). 這樣的方式會讓整個流程在
表現上變得清楚.
channels
channel 的通訊, 需要一個 sender 和一個 receiver, 當 sender 和 receiver 都 ready 時候, 訊息才會成功的傳遞.
import "fmt"
func main(){
s := mack(chan string) //宣告一個 channel 變數
s <- "hello" //寫入 channel (sender)
val <- s //讀取 channel (receiver)
fmt.Println(val)
}
上例說明了如何宣告 channel 變數, 寫入 channel, 讀取 channel.
Golang 入門初體驗
Go 語法
goroutine - channels
但是 code 無法跑, compiler 會顯示 dead lock.
因為執行到 s <- "hello" 這步的時候, sender 就會進入 ready 狀態.
然後就停住了, 也就是他不會執行到 val := <- s .
這時我們建立一個 goroutine 去跑 s <- "hello"
import "fmt"
func main(){
s := make(chan string) //宣告一個 channel 變數
go func(){
s <- "hello" //寫入 channel (sender)
}()
val := <- s //讀取 channel (receiver)
fmt.Println(val)
}
Golang 入門初體驗
Go 語法
goroutine - channels
執行順序就是
1. 建立一個 goroutine //此時 s <- "hello" 還沒執行
2. 執行 val := <- s //s 空的, receiver ready (停住)
3. 執行 s <- "hello" //sender 將訊息寫入 s, sender ready
4. val := <- s //成功讀取 s, (因為 receiver, sender 都 ready)
5. fmt.Println(val)
goroutine 不見得會比較慢執行. 不過重點不在這, 就不多描述了.
所以要看執行的順序就要注意這原則 "當 sender 和 receiver 都 ready 時候, 訊息才會成功的傳遞. "
再舉一個例子, 請問順序式如何?
Golang 入門初體驗
Go 語法
goroutine – channels
import "fmt"
func main(){
s := make(chan string)
go func() {
for i := 0; i < 3; i++ {
fmt.Println("sender hello",i)
s <- fmt.Sprintf("receiver hello %d", i)
}
}()
for i := 0; i < 3; i++ {
val := <-s
fmt.Println(val)
}
}
Golang 入門初體驗
Go 語法
goroutine – channels
結果
sender hello 0
sender hello 1
receiver hello 0
receiver hello 1
sender hello 2
receiver hello 2
有對嗎?程式碼順序是這樣
1. 建立一個 goroutine
2. 執行 val := <- s //s 空的, receiver ready (停住)
[sender hello 0]
3. 執行 s <- fmt.Sprintf.. //sender 將訊息寫入 s, 傳訊成功
[sender hello 1]
4. 執行 s <- fmt.Sprintf.. //s 有值, sender ready(停住)
5. val := <-s //讀到 s 的值
[receiver hello 0]
6. val := <-s //s 空的, receiver ready, 傳訊成功
[receiver hello 1]
7. val := <-s //s 空的, receiver ready (停住)
[sender hello 2]
8. 執行 s <- fmt.Sprintf.. //sender 將訊息寫入 s, 傳訊成功
9. val := <-s //讀到 s 的值
[sender hello 2]
http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
Golang 入門初體驗
Go 語法
goroutine – channels
另外我們可以修改 channel 的大小為 2
import "fmt"
func main(){
s := make(chan string,2)
go func() {
for i := 0; i < 3; i++ {
fmt.Println("sender hello",i)
s <- fmt.Sprintf("receiver hello %d", i)
}
}()
for i := 0; i < 3; i++ {
val := <-s
fmt.Println(val)
}
}
結果
sender hello 0
sender hello 1
sender hello 2
receiver hello 0
receiver hello 1
receiver hello 2
http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
Golang 入門初體驗
Go 語法
defer panic recover
defer
先看以下範例
func f(){
for i := 0 ; i < 5 ; i++{
fmt.Println(i)
}
fmt.Println("f finish")
}
此時的結果是
0
1
2
3
4
f finish
Golang 入門初體驗
Go 語法
defer panic recover
如果再 fmt.Println 前面加上 defer
func f(){
for i := 0 ; i < 5 ; i++{
defer fmt.Println(i)
}
fmt.Println("f finish")
}
結果就變成
f finish
4
3
2
1
0
Golang 入門初體驗
Go 語法
defer panic recover
defer 是讓 fmt.Println(0) , fmt.Println(1) , fmt.Println(2) , fmt.Println(3) , fmt.Println(4) 依序放到清單中, 等到
func f 結束前, 再依據 Last-In-First-Out (LIFO) 的順序 call 清單中的 function.
這樣功能提供了什麼的好處?
我們再看以下的例子
Golang 入門初體驗
Go 語法
defer panic recover
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
return
}
written, err = io.Copy(dst, src)
dst.Close()
src.Close()
return
}
Golang 入門初體驗
Go 語法
defer panic recover
這個例子有個 bug, 就是當 os.Create(dstName) 失敗的時候 function 就會 return, 而 src.Close() 就沒有執行
到了.
所以可以改成這樣
Golang 入門初體驗
Go 語法
defer panic recover
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
src.Close()
return
}
written, err = io.Copy(dst, src)
dst.Close()
src.Close()
return
}
Golang 入門初體驗
Go 語法
defer panic recover
但是如果開多個檔案? 那會很麻煩
所以我們利用 defer 來修改
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
這時不管如何, 都會執行 close function.
Golang 入門初體驗
Go 語法
defer panic recover
但是如果開多個檔案? 那會很麻煩
所以我們利用 defer 來修改
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
這時不管如何, 都會執行 close function.
參考網站
https://blog.golang.org/defer-panic-and-recover
panic recover
go 沒有 try catch , 原因是 go 的開發者認為, 當過多 try catch 時
會造成程式碼很難閱讀. 所以提供了 panic recover 優雅的解決這
個問題.
Golang 入門初體驗
Go 後續
GoWeb
Go Bot (Line、Facebook Message、Slack、Telegram、 ……..)
Go 機器學習
Go 物聯網
Golang 入門初體驗

Más contenido relacionado

La actualidad más candente

版本控制 使用Git & git hub
版本控制   使用Git & git hub版本控制   使用Git & git hub
版本控制 使用Git & git hub
維佋 唐
 
Python topic re
Python topic rePython topic re
Python topic re
cri fan
 
Git tutorial for windows user (給 Windows user 的 Git 教學)
Git tutorial for windows user (給 Windows user 的 Git 教學)Git tutorial for windows user (給 Windows user 的 Git 教學)
Git tutorial for windows user (給 Windows user 的 Git 教學)
Cloud Tu
 

La actualidad más candente (15)

Git由超淺入超深
Git由超淺入超深Git由超淺入超深
Git由超淺入超深
 
Golang server design pattern
Golang server design patternGolang server design pattern
Golang server design pattern
 
Git in a nutshell
Git in a nutshellGit in a nutshell
Git in a nutshell
 
該怎麼樣(認真的)部署你的 Python Web 應用程式?
該怎麼樣(認真的)部署你的 Python Web 應用程式?該怎麼樣(認真的)部署你的 Python Web 應用程式?
該怎麼樣(認真的)部署你的 Python Web 應用程式?
 
Git Tutorial 教學
Git Tutorial 教學Git Tutorial 教學
Git Tutorial 教學
 
Day01. 安裝 Ktor
Day01. 安裝 KtorDay01. 安裝 Ktor
Day01. 安裝 Ktor
 
幸福快樂的完美結局
幸福快樂的完美結局幸福快樂的完美結局
幸福快樂的完美結局
 
Python 2-基本語法
Python 2-基本語法Python 2-基本語法
Python 2-基本語法
 
版本控制 使用Git & git hub
版本控制   使用Git & git hub版本控制   使用Git & git hub
版本控制 使用Git & git hub
 
Python topic re
Python topic rePython topic re
Python topic re
 
Bootstrap個人網站 20141117
Bootstrap個人網站 20141117Bootstrap個人網站 20141117
Bootstrap個人網站 20141117
 
Git tutorial for windows user (給 Windows user 的 Git 教學)
Git tutorial for windows user (給 Windows user 的 Git 教學)Git tutorial for windows user (給 Windows user 的 Git 教學)
Git tutorial for windows user (給 Windows user 的 Git 教學)
 
FreeBSD documentation translation
FreeBSD documentation translationFreeBSD documentation translation
FreeBSD documentation translation
 
Homebrew Updater
Homebrew UpdaterHomebrew Updater
Homebrew Updater
 
MPI use c language
MPI use c languageMPI use c language
MPI use c language
 

Similar a Golang 入門初體驗

2006 recycle opensourceprojects
2006 recycle opensourceprojects2006 recycle opensourceprojects
2006 recycle opensourceprojects
George Ang
 
Recycle Open Source Projects
Recycle Open Source ProjectsRecycle Open Source Projects
Recycle Open Source Projects
George Ang
 
Python 入门
Python 入门Python 入门
Python 入门
kuco945
 
Using google appengine_1027
Using google appengine_1027Using google appengine_1027
Using google appengine_1027
Wei Sun
 
Using google appengine (2)
Using google appengine (2)Using google appengine (2)
Using google appengine (2)
Wei Sun
 
Groovy简介
Groovy简介Groovy简介
Groovy简介
profeter
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學
Sita Liu
 
Groovy:Candy for Java Developers
Groovy:Candy for Java DevelopersGroovy:Candy for Java Developers
Groovy:Candy for Java Developers
foxgem
 
Django敏捷开发 刘天斯
Django敏捷开发 刘天斯Django敏捷开发 刘天斯
Django敏捷开发 刘天斯
liuts
 

Similar a Golang 入門初體驗 (20)

Introduction to Golang final
Introduction to Golang final Introduction to Golang final
Introduction to Golang final
 
Golangintro
GolangintroGolangintro
Golangintro
 
Go 語言基礎簡介
Go 語言基礎簡介Go 語言基礎簡介
Go 語言基礎簡介
 
Go集成c&c++代码
Go集成c&c++代码Go集成c&c++代码
Go集成c&c++代码
 
2006 recycle opensourceprojects
2006 recycle opensourceprojects2006 recycle opensourceprojects
2006 recycle opensourceprojects
 
Recycle Open Source Projects
Recycle Open Source ProjectsRecycle Open Source Projects
Recycle Open Source Projects
 
Go语言: 互联网时代的C
Go语言: 互联网时代的CGo语言: 互联网时代的C
Go语言: 互联网时代的C
 
Python 入门
Python 入门Python 入门
Python 入门
 
Using google appengine_1027
Using google appengine_1027Using google appengine_1027
Using google appengine_1027
 
《Python 3.5 技術手冊》第二章草稿
《Python 3.5 技術手冊》第二章草稿《Python 3.5 技術手冊》第二章草稿
《Python 3.5 技術手冊》第二章草稿
 
Using google appengine (2)
Using google appengine (2)Using google appengine (2)
Using google appengine (2)
 
Groovy简介
Groovy简介Groovy简介
Groovy简介
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
 
Grails敏捷项目开发
Grails敏捷项目开发Grails敏捷项目开发
Grails敏捷项目开发
 
1 C入門教學
1  C入門教學1  C入門教學
1 C入門教學
 
Vim hacks
Vim hacksVim hacks
Vim hacks
 
開放原始碼的回收與再利用
開放原始碼的回收與再利用開放原始碼的回收與再利用
開放原始碼的回收與再利用
 
JCConf 2015 TW 高效率資料爬蟲組合包
JCConf 2015 TW 高效率資料爬蟲組合包JCConf 2015 TW 高效率資料爬蟲組合包
JCConf 2015 TW 高效率資料爬蟲組合包
 
Groovy:Candy for Java Developers
Groovy:Candy for Java DevelopersGroovy:Candy for Java Developers
Groovy:Candy for Java Developers
 
Django敏捷开发 刘天斯
Django敏捷开发 刘天斯Django敏捷开发 刘天斯
Django敏捷开发 刘天斯
 

Más de 政斌 楊

Más de 政斌 楊 (20)

iOS swift 玩 soket 聊天通訊程式
iOS swift 玩 soket 聊天通訊程式iOS swift 玩 soket 聊天通訊程式
iOS swift 玩 soket 聊天通訊程式
 
iOS Swift & OCR 玩文字辨識
iOS Swift & OCR 玩文字辨識iOS Swift & OCR 玩文字辨識
iOS Swift & OCR 玩文字辨識
 
深入學習 iBeacon 之 iOS swift 程式設計
深入學習 iBeacon 之 iOS swift 程式設計深入學習 iBeacon 之 iOS swift 程式設計
深入學習 iBeacon 之 iOS swift 程式設計
 
Android Studio & Cloud Vision API 玩圖像辨識
Android Studio & Cloud Vision API 玩圖像辨識Android Studio & Cloud Vision API 玩圖像辨識
Android Studio & Cloud Vision API 玩圖像辨識
 
iOS swift & Cloud Vision API 玩圖像辨識
iOS swift & Cloud Vision API 玩圖像辨識iOS swift & Cloud Vision API 玩圖像辨識
iOS swift & Cloud Vision API 玩圖像辨識
 
Android studio 之 i beacon 藍芽應用開發學習
Android studio 之 i beacon 藍芽應用開發學習Android studio 之 i beacon 藍芽應用開發學習
Android studio 之 i beacon 藍芽應用開發學習
 
Python vs json 玩open data
Python vs json 玩open dataPython vs json 玩open data
Python vs json 玩open data
 
iOS swift 之 iBeacon 藍芽應用開發學習
iOS swift 之 iBeacon 藍芽應用開發學習iOS swift 之 iBeacon 藍芽應用開發學習
iOS swift 之 iBeacon 藍芽應用開發學習
 
Android studio 2.2 初體驗 &amp; 玩 face book sdk
Android studio 2.2 初體驗 &amp; 玩 face book sdkAndroid studio 2.2 初體驗 &amp; 玩 face book sdk
Android studio 2.2 初體驗 &amp; 玩 face book sdk
 
Python 入門初體驗
Python 入門初體驗Python 入門初體驗
Python 入門初體驗
 
Python 入門初體驗(程式語法)
Python 入門初體驗(程式語法)Python 入門初體驗(程式語法)
Python 入門初體驗(程式語法)
 
I os swift 3.0 初體驗 &amp; 玩 facebook sdk
I os swift 3.0 初體驗 &amp; 玩 facebook sdkI os swift 3.0 初體驗 &amp; 玩 facebook sdk
I os swift 3.0 初體驗 &amp; 玩 facebook sdk
 
Android studio 之 fcm 推播服務
Android studio 之 fcm 推播服務Android studio 之 fcm 推播服務
Android studio 之 fcm 推播服務
 
I os swift 之 fcm 推播服務
I os swift 之 fcm 推播服務I os swift 之 fcm 推播服務
I os swift 之 fcm 推播服務
 
Android &amp; fire base 玩上雲端囉
Android &amp; fire base 玩上雲端囉Android &amp; fire base 玩上雲端囉
Android &amp; fire base 玩上雲端囉
 
iOS Swift & FireBase 玩上雲端囉
iOS Swift & FireBase 玩上雲端囉iOS Swift & FireBase 玩上雲端囉
iOS Swift & FireBase 玩上雲端囉
 
Android studio 接力使力之玩 open data
Android studio 接力使力之玩 open dataAndroid studio 接力使力之玩 open data
Android studio 接力使力之玩 open data
 
iOS swift 接力使力之玩 open data
iOS swift 接力使力之玩 open dataiOS swift 接力使力之玩 open data
iOS swift 接力使力之玩 open data
 
Android app 入門第一步
Android app 入門第一步Android app 入門第一步
Android app 入門第一步
 
再接再勵學 Swift 程式設計
再接再勵學 Swift 程式設計再接再勵學 Swift 程式設計
再接再勵學 Swift 程式設計
 

Último

1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂
1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂
1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂
PUAXINYEEMoe
 
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
michaelell902
 
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
PUAXINYEEMoe
 

Último (9)

啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx
啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx
啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx
 
1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...
1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...
1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...
 
1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂
1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂
1.1.3急救你必须懂四年级设计与工艺练习活页练习单元一四年级设计与工艺急救你必须懂
 
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
 
Math Chapter3-教學PPT第03單元形體關係、體積與表面積Grade Six
Math Chapter3-教學PPT第03單元形體關係、體積與表面積Grade SixMath Chapter3-教學PPT第03單元形體關係、體積與表面積Grade Six
Math Chapter3-教學PPT第03單元形體關係、體積與表面積Grade Six
 
taibif_資料標準概念介紹_20240509_20240509_20340509.pdf
taibif_資料標準概念介紹_20240509_20240509_20340509.pdftaibif_資料標準概念介紹_20240509_20240509_20340509.pdf
taibif_資料標準概念介紹_20240509_20240509_20340509.pdf
 
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
 
1.🎉成绩单,你的成绩! 💡🔥每个人都有自己的成绩单,它记录着我们努力的成果。但有时候,看着这些数字,却发现它们好像在嘲笑我?别担心,让我来告诉你们怎么改...
1.🎉成绩单,你的成绩! 💡🔥每个人都有自己的成绩单,它记录着我们努力的成果。但有时候,看着这些数字,却发现它们好像在嘲笑我?别担心,让我来告诉你们怎么改...1.🎉成绩单,你的成绩! 💡🔥每个人都有自己的成绩单,它记录着我们努力的成果。但有时候,看着这些数字,却发现它们好像在嘲笑我?别担心,让我来告诉你们怎么改...
1.🎉成绩单,你的成绩! 💡🔥每个人都有自己的成绩单,它记录着我们努力的成果。但有时候,看着这些数字,却发现它们好像在嘲笑我?别担心,让我来告诉你们怎么改...
 
taibif_開放資料流程-清理資料01-通則_20240509_20240509.pdf
taibif_開放資料流程-清理資料01-通則_20240509_20240509.pdftaibif_開放資料流程-清理資料01-通則_20240509_20240509.pdf
taibif_開放資料流程-清理資料01-通則_20240509_20240509.pdf
 

Golang 入門初體驗

  • 2. 學習主題 • 社群成立目的簡介 • 自我介紹與哈啦 • 功力複習 • 程式實作(Golang) • 問題與交流
  • 3. 個人簡介 諸葛魔斌 工作室:諸葛魔斌科技創作室 學歷:高應大---工管系(非資訊科系) E-Mail:chugermobin@gmail.com 官方網站:http://twcts.com Facebook:https://goo.gl/volM7Z 粉絲團 :https://goo.gl/LI08wh 社群 :https://goo.gl/kjCsz1 Line (id) :http://goo.gl/ayGW7d Line@ :http://goo.gl/pQHjWH Line Bot :http://goo.gl/ljdxfV Play商店:http://goo.gl/CkVdsd App Store:http://apple.co/1Qehd64 專長:VB(VBA)、C#、Java(Android)、Swift(iOS)、PHP、Python、Conrona、 Golang、Unity、MySQL、FreeBSD、Server架設、CAD 、 …… 楊政斌
  • 4. 學習程式的歷程 學生時期:打電動,沒有日夜的界限 二專畢業:初次接觸 dBase、Lotus  使用 Clipper 做經銷存、應收付帳系統 工作階段1:接觸 Office,開始使用Excel(Lotus) 工作階段2:品保工作,自學圖表、函數、VBA,做出自動化品管系統 興趣展開:自學VB,製作ERP系統,接觸Linux、FreeBSD,自學架設Server  諸葛魔斌誕生 大學時期:半自學 Android App(Java)、C#、iOS App(Swift) 工作轉變:成立諸葛魔斌科技創作室,接案學習,救國團電腦資訊講師 實績:
  • 5. Golang 入門初體驗 Go,又稱golang,是Google開發的一種靜態強型別、編譯型,並發型,並具有垃圾回收功能的程 式語言。 羅伯特·格瑞史莫,羅勃·派克(Rob Pike)及肯·湯普遜於2007年9月開始設計Go語言,稍後Ian Lance Taylor, Russ Cox加入專案中。Go語言是基於Inferno作業系統所開發的。Go語言於2009 年11月正式宣布推出,成為開放原始碼專案,並在Linux及Mac OS X平台上進行了實現,後追加 Windows系統下的實作。 Go語言的語法接近C語言,但是對於變數的聲明是不同的,其他語法不同之處是For迴圈和if判斷語 句不需要用小括弧括起來。Go語言支援垃圾回收功能。Go語言的並列模型是以東尼·霍爾的交談循 序程式(CSP)為基礎,採取類似模型的其他語言套件括Occam和Limbo,但它也具有Pi運算的特 徵,比如通道傳輸。 與C++相比,Go語言並不包括如例外處理、繼承、泛型、斷言、虛擬函式等功能,但增加了slice型、 並行、管道、垃圾回收、介面(interface)等特性的語言級支援。當然,Google對於泛型的態度 還是很開放的,但在該語言的常見問題列表中,對於斷言的存在,則持負面態度,同時也為自己不 提供型別繼承來辯護。不同於Java,Go語言內嵌了關聯陣列(也稱為雜湊表(hashes)或字典 (dictionaries)),就像字串類型一樣。
  • 6. Golang 入門初體驗 當前有兩個Go語言的編譯器的分支。官方編譯器gc和gccgo。官方編譯器在初期使用C寫成,後用go 重寫從而實作自舉。Gccgo是一個使用標準GCC作為後端的Go編譯器。 官方編譯器支援跨平台編譯(但不支援CGO),允許將源碼編譯為可在目標系統、架構上執行的二進 位檔案。 Go 在2007年9月開始為 google 內部員工的 20% 自由時間的實驗項目, 目的為改善公司內部的開發速 度. 隔了一年受到 google 公司的重視和支持, 2009年11 月對外發佈第一版本. 過去 google 常用的語 言有 c , java , python來開發他們的服務. 但是這些語言是在創造的時候的硬體環境, 和現在有很大的 不同. 而 Golang 在設計的時候就考慮了這些架構, 所以在開發上和過去的語言比較起來有很大的優勢. Go的關鍵字不多(目前約25個 c 37個,c++ 84個而且還在增加中), 學習上很容易上手, 再加上有不少和 c 的關鍵字重複, 所以如果你原本就是寫c/c++的人, 在轉換上會相對其他語言容易. 平均下來效能是輸c, 可是贏其他語言如 ruby(ror), php, java, python等語言. 主要原因的先天優勢是, 他語言架構設計非常單純, 並不像是如物件導向語言這麼的大. 再來是他不是直譯語言. 光是這兩點優 勢, 讓他有更好的體質去有較好的執行效率. 已經有很多案例, 在開發伺服器的軟體時, 因為效能問題而 改換 go 去寫, 結果讓他們減少了伺服器的數量就可以達到原本的效能, 增加了服務的效率也省下了硬 體成本.
  • 7. Golang 入門初體驗 goroutine 這是Go的最大特色之一, thread 的使用是非常消耗系統資源的, 而且當你使用越來越多時管理上也越 困難. 而 goroutine 有輕巧低消耗資源的特性, 而這優點在於系統資源的消耗也會比較少. 可以使用 c library 他可以使用 c library, 解決新語言在 library 上的不足. 不過基本上 go 本身的 lib 已經很豐富了. Unicode slice map 都有支援. 目前越來越多公司用 go 來寫他們網站後端的系統, 過去 google 在寫他的服務大多使用 c + python, python 是個很簡潔的語言在建構服務是非常快的, c 是用來解決效能上的問題, 現在內部也都慢慢轉成 go 來寫. 在2014年TIOBE四月程式語言排名已經到第30名, 2013基本上都是在50名以外, 而且我相信 這名次會持續在進步. 第一個 go 程式 package main import "fmt“ func main () { fmt.Println("Hello , World!") }
  • 8. Golang 入門初體驗 Go 安裝 http://golang.org/dl/ Windows: 安裝好 GO 後, 還需要 GCC 編譯環境, 因為 Mac 的 Xcode 本身就有 GCC, windows 沒有, 所以 選擇了 mingw 這個輕量型的 GCC http://blog.jex.tw/blog/2013/12/17/windows-install-gcc-compiler-mingw/ 設定 GOPATH, 這是放一些你自己或 go get from github 存放的地方 1. 在 c:Go 下建立 mygo 資料夾, 並且在 mygo 下建立三個資料夾 src, pkg, bin 2. 設定環境變數 GOROOT : C:Go GOPATH : C:Gomygo PATH : 在最後面加上 ;%GOROOT%bin;%GOPATH%bin;C:Program Files (x86)Gitbin 除了加上 GOROOTbin、GOPATHbin, 也可視需求加上 git bin 的路徑,重新啟動 cmd 使變數 生效
  • 9. Golang 入門初體驗 Go 執行 https://golang.org/cmd/go/ go run 要撰寫第一個 Hello, World 程式,你可以建立一個 main.go,在當中撰寫以下的內容: package main import "fmt" func main() { fmt.Println("Hello, World") fmt.Println("哈囉!世界!") }
  • 10. Golang 入門初體驗 Go 執行 每個 .go 原始碼,都必須從 package 定義開始,而對於包括程式進入點 main 函式的 .go 原始碼, 必須是在 package main 之中,為了要能輸出訊息,這邊使用了 fmt 套件(package)之中的 Println 函式,開頭的大寫 P 表示這是個公開的函式,可以在套件之外進行呼叫。 Go 的創建者之一也是 UTF-8 的創建者,因此,Go 可以直接處理多國語言,只要你確定編輯器 編碼為 UTF-8 就可以了,如果你使用 vim,可以在 vim 的命令模式下輸入 :set encoding=utf-8, 或者是在 .vimrc 之中增加一行 set encoding=utf-8。 Go 可以用直譯的方式來執行程式,第一個 Hello, World 程式就是這麼做的,執行 go run 指定 你的原始碼檔名就可以了: $ go run main.go Hello, World 哈囉!世界! package 與 GOPATH
  • 11. Golang 入門初體驗 Go 執行 那麼,一開始的 package 是怎麼回事?試著先來建立一個 hello.go: package hello import "fmt" func HelloWorld() { fmt.Println("Hello, World") }
  • 12. Golang 入門初體驗 Go 執行 記得,package 中定義的函式,名稱必須是以大寫開頭,其他套件外的程式,才能進行呼叫,若 函式名稱是小寫,那麼會是套件中才可以使用的函式。 接著,原本的 main.go 修改為: package main import "hello" func main() { hello.HelloWorld() }
  • 13. Golang 入門初體驗 Go 執行 現在顯然地,main.go 中要用到方才建立的 hello 套件中的 HelloWorld 函式,這時 package 的 設定就會發揮一下效用,你得將 hello.go 移到 src/hello 目錄之中,也就是目錄名稱必須符合 package 設定之名稱。 而 src/hello 的位置,必須是在 GOROOT 底下,或者是 GOPATH 底下,當 Go 需要某個某個套 件中的元素時,會分別到這兩個環境變數的目錄之中,查看是否有相應於套件的原始碼存在。 為了方便,通常會設定 GOPATH,例如,指向目前的工作目錄: export GOPATH=~workspacego 雖然目前 GOPATH 中只一個目錄,不過 GOPATH 中可以設定數個目錄
  • 14. Golang 入門初體驗 Go 執行 go build 這個命令主要用於測試編譯。在包的編譯過程中,在必要情況下,還可以同時編譯與之關聯的包。 -普通包:執行完go build ,不會產生任何檔,如果需要在$GOPATH/pkg下生成相應檔,則要 執行go install. -main 包:執行完go build,會在目前的目錄下生成一個可執行檔,如果需要在$GOPATH/bin下生成 對應檔,需要執行go install 或使用 go build -o outputpath/ 如果只想編譯某個檔,只需在在後面加上檔案名即可,例如:go build hello.go 非main包在預設情況下編譯輸出的是package名,main包是第一個原始檔案的檔包,也還可以指定編 譯輸出的檔案名,例如,go build -o xialingsc.exe
  • 15. Golang 入門初體驗 Go 執行 go build go build 會忽略目錄下以"_"或"."開頭的go文件 如果原始程式碼針對不同的作業系統需要不同的處理,那麼可以根據不同的作業系統尾碼來命名檔。 例如,readfile_linux.go,readfile_drawin.go,readfile_windows.go.go build 會選擇性編譯 檔,Linux系統只編譯readfile_linux.go,其他文件則被忽略。
  • 16. Golang 入門初體驗 Go 執行 go build 如果想編譯原始碼為可執行檔,那麼可以使用 go build,例如,直接 go build main.go,就會在 執行指令的目錄下,產生一個名稱為 main 的可執行檔,可執行檔的名稱是來自己指定的原始碼 檔案主檔名,執行產生出來的可執行檔就會顯示 Hello, World。 你也可以建立一個 bin 目錄,然後執行 go build -o bin/main main.go,這樣產生出來的可執行 檔,就會被放在 bin 底下,如果想將原始碼全部放在 src 底下管理,那麼就將 main.go 放到 src/main 底下,然後執行 go build -o bin/main src/main/main.go。 go install 每次使用 go build,都是從原始碼編譯為可執行檔,這比較沒有效率,如果想要編譯時更有效率 一些,可以使用 go install,例如,在目前既有的目錄與原始碼架構之下,執行 go install main
  • 17. Golang 入門初體驗 Go 執行 go build ~go |~bin/ | |-main |~pkg/ | `~linux_arm/ | `-hello.a |~src/ | |~hello/ | | `-hello.go | |~main/ | | `-main.go go install packageName 表示要安裝指定名稱的套件,如果是 main 套件,那麼會在 bin 中產生 可執行檔,如果是公用套件,那麼會在 pkg 目錄的 $GOOS_$GOARCH 目錄中產生 .a 檔案
  • 18. Golang 入門初體驗 Go 執行 go build 可以使用 go env 來查看 Go 使用到的環境變數,例如: $ go env GOARCH="arm" GOBIN="" GOEXE="" GOHOSTARCH="arm" GOHOSTOS="linux" GOOS="linux" GOPATH="/root/workspace/go" GORACE="" GOROOT="/opt/go" GOTOOLDIR="/opt/go/pkg/tool/linux_arm" GO15VENDOREXPERIMENT="" CC="gcc" GOGCCFLAGS="-fPIC -marm -pthread -fmessage-length=0" CXX="g++" CGO_ENABLED="1"
  • 19. Golang 入門初體驗 Go 執行 go build .a 檔案是編譯過後的套件,因此,你看到的 hello.a,就是 hello.go 編譯之後的結果,如果編譯 時需要某個套件,而對應的 .a 檔案存在,且原始碼自上次編譯後未曾經過修改,那麼就會直接使 用 .a 檔案,而不是從原始碼開始編譯起。 go clean 用來移除當前源碼包裡編譯生成的檔,這些檔包括,_obj(舊的objects目錄,Makefiles遺留), _test(舊的test目錄),_testmain.go(舊的gotest文件),test.out、build.out(舊的test記錄) *.[568ao] object文件,DIR(.exe)(由go build產生),DIR.test(.ext)(由go test -c產生), MAINFILE(.exe) (由go build MAINFILE.go產生) 該命令最大的作用,清除編譯文件後,上傳git,保持源碼清潔。
  • 20. Golang 入門初體驗 Go 執行 os.Args 那麼,如果想在執行 Go 程式時使用命令列引數呢?可以使用 os 套件的 Args,例如,寫一個 main.go: package main import "os" import "fmt" func main() { fmt.Printf("Command: %sn", os.Args[0]) fmt.Printf("Hello, %sn", os.Args[1]) }
  • 21. Golang 入門初體驗 Go 執行 os.Args 是個陣列,索引從 0 開始,索引 0 會是編譯後的可執行檔名稱,索引 1 開始會是你提供 的引數,例如,在執行過 go build 或 go install 之後,如下直接執行編譯出來的執行檔,會產生 的訊息是… $ ./bin/main Justin Command: ./bin/main Hello, Justin go doc
  • 22. Golang 入門初體驗 Go 執行 fmt 的 Printf,就像是 C 的 printf,可用的格式控制字元可參考 Package fmt 的說明。實際上, Go 本身附帶了說明文件,可以執行 go doc <pkg> <sym>[.<method>] 來查詢說明。例如: $ go doc fmt.Printf func Printf(format string, a ...interface{}) (n int, err error) Printf formats according to a format specifier and writes to standard output. It returns the number of bytes written and any write error encountered.
  • 23. Golang 入門初體驗 Go 執行 go fmt 幫助格式化寫好的代碼檔,讓寫代碼時不關心格式,寫完後,輕鬆執行go fmt 檔案名.go就好 提高效率。更多的時候可以採用gofmt,同時增加-w的參數,否則格式化結果不會寫入檔,例如: gofmt -w src 來格式整個項目。 go get 動態獲取遠端代碼。這個代碼內部分為兩部分,一是下載源碼包,另一步是執行go install 為了讓go get正常使用,需保證安裝了合適的源碼管理工具,並將這些命令加入到PATH中。 可通過go help remote 瞭解更多。 go test 執行這個命令會自動讀取源碼目錄下名為*_test.go檔,生成並運行測試用的可執行檔。 預設情況下不需要任何參數,也可帶上參數,具體可參見go help testflag
  • 24. Golang 入門初體驗 Go 執行 go doc 如何查看相應的package文檔呢? 如果是builtin包,可以執行go doc builtin;如果是http包,執行go doc net/http; 查看某個包裡面的函數,類似執行 godoc fmt Println,還可以查看相應代碼 godoc -src fmt Println 很棒的一點是,可以在終端執行godoc -http=:埠號,例如godoc -http=:8080 ,就可以在 流覽器中敲入127.0.0.1:8080進行文檔內容的查看。 其他命令 go fix 用來修復以前老版本的代碼到新版本 go version 查看go當前的版本 go env 查看當前go的環境變數 go list 列出當前全部安裝的package go run 編譯並運行go語言程式
  • 25. Golang 入門初體驗 Go IDEs IDEs 有以下幾種,使用文字編輯器亦可完成程式編輯,再至Command Line執行編譯 Lite IDE GoSublime Visual Studio Code Goclipse VIM / VIM-go
  • 26. Golang 入門初體驗 Go 語法 (參考 https://polor10101.gitbooks.io/golang_note/content/about_golang.html) variable 變數 雖然號稱和 c 類似, 不過 go 在變數的命名上有很大的不同, 他是以 type 放後面為原則 以下表示宣告一個變數 x 且他是整數型態. var x int 如果要給他初始值, 有以下幾種方式 給予初始值 var x int = 10 var y = 20 var z int z = 30 k := 40 常數 const PI = 3.1415 const NAME = "Nelson" 常數不需要給定 type, 只要直接給予值即可. 而且不能用 ':=' 的方式給予初始值. 你可以發現每行的結尾少了分號 ';', 是的 go 省略分號, 只要斷行來分就好.
  • 27. Golang 入門初體驗 Go 語法 函式 函式的宣告方式也和 c 不同 func add( a int , b int){ c := a + b } 如果要回傳東西 func add( a int , b int) int{ c := a + b return c } 但是還是維持 type 在後面的原則 在此在大括號的位置也有規定, 如例子所示
  • 28. Golang 入門初體驗 Go 語法 函式 你也可以 func add( a int , b int) int{ } 但是不可以採用對齊的方式 func add( a int , b int) int { } 從以上例子來看, 會發現 go 在程式的風格上有強制規定, 不符合規定會有 error
  • 29. Golang 入門初體驗 Go 語法 函式 有幾點初學的時候有點不習慣 每行 code 不需要分號 ; 大括號的排版方式 import 某個 lib 或是宣告某變數但是實際卻沒有使用 宣告改成這個方式, 官方是說可以增加閱讀性. why? 這部份在其他章節會有描述 另外可以用變數直接指向 function func add(a int,b int) int{ return a+b }
  • 30. Golang 入門初體驗 Go 語法 關於語法 go 在語法中做了改變, 官方的說法是, 改這樣的原因是因為這樣比較好閱讀. 接著來比較 c 和 go 的語法 以宣告 variable 來看 int add; //c var add int //go go 還多一個 var, 似乎也沒有比較方便 以 function 來看 int add(int a, intb); //c func add(a int, b int)int //go 也還好, 不過比較起來 go 比較容易分辨出是 variable 還是 function, 但是差距也沒有很大, 而且 go 還需要多打 字.
  • 31. Golang 入門初體驗 Go 語法 關於語法 如果宣告一個 function pointer 然後輸入一個 function pointer 變數 int (*fp)(int (*ff)(int x, int y), int b) //c f func(func(int,int) int, int) int //go c 已經有點讓人混亂了, 且不好閱讀. go 這樣是不是有比較清楚? 個人是覺得有, 還很明顯. 再加個回傳 function pointer 的宣告比較. int (*(*fp)(int (*)(int, int), int))(int, int) //c f func(func(int,int) int, int) func(int, int) int //go 結論 : 真的有差. f := add f(10,20)
  • 32. Golang 入門初體驗 Go 語法 loop 迴圈 以 c 來說迴圈有 for , while , do while 三個關鍵字. 在 go 裡面只有一個 for 來達到全部 以 for 迴圈來說 c 為 int i = 0; int sum = 0; for( i = 0 ; i < 10 ; ++i ) { sum += i; } 以下為 go 的 for 迴圈範例 sum := 0 for i := 0 ; i < 10 ; ++i { sum += i } 從範例中可以看到 "( )" 省略了, 再來兩個中夸號並不是對齊的
  • 33. Golang 入門初體驗 Go 語法 loop 迴圈 c 的 do while 迴圈 int i = 0; do{ i += 1 }while( i < 10 ); go 中為 i := 0 for i < 100 { i += 1 } c 的無限 while 迴圈 while(1) { } go 的 for { } 以上為 go 和 c 的迴圈使用比較. 從中可以了解一些語法上 的差別
  • 34. Golang 入門初體驗 Go 語法 if switch 和 c 不同的是, if 不需要小括號, 另外大括號必須要有, 並且強制是範例的排版方式, 否則會有 error if a > 0 { fmt.Println(a) } 個人是習慣對齊的方法, 不過這樣的強制規定可以讓多人開發專案的程式碼有一致性, 這也是個好處. switch 也是同樣的規定, 並且不需要加上 'break' 如以下所示 switch i { case 1 : fmt.Println(1) case 2 : fmt.Println(2) default : fmt.Println("default") }
  • 35. Golang 入門初體驗 Go 語法 Array array 的宣告 var a [5]int //宣告一個大小5的 int array var b []int //宣告空的 int array var c = []int{1,2,3,4,5}//宣告一個大小5的 int array, 並給初始值 如果要列印 array 裡面的值, 你可以使用 range 知道 array 目前的 index import "fmt" func main() { var a = [4]int {1,2,3,4} for i := range a { fmt.Println(a[i]) } }
  • 36. Golang 入門初體驗 Go 語法 Array 初始話也可以改成 var a = [4]int { 1, 2, 3, 4, } 其中 4 的後面記得要有逗號 ','
  • 37. Golang 入門初體驗 Go 語法 Slice 相對於 array, slice 提供了彈性, 不需要指定大小 是由三個元件組成 ptr len cap 其中 prt 是指向一個 array 的指標, 如圖所示
  • 38. Golang 入門初體驗 Go 語法 Slice len 為實際資料長度, cap 表示容量 宣告的方式為 a := []int 此時的 len , cap 都為 0 你可以用 make 來宣告變數並指定 len 和 cap 的值 a := make([]int,5,10) 其中 5 為len, 10 為 cap
  • 39. Golang 入門初體驗 Go 語法 Slice 也可以不指定 cap 寫成 a := make([]int,5) 這時 len 為 5 , cap 為 5 另外給定初始值的宣告 var a = []int {1,2,3,4,5} 如果要一個變數指向 a b := a[2:4] c := a[:]
  • 40. Golang 入門初體驗 Go 語法 Slice 其中 b 為 3 , 4. a[2:4] 的 2 表示指向 a index = 2 的位置, 4 表示為結尾在 index = 4(不包含), 所以則 length 為 2, 另外由於 array 是連續的, 所以 cap = 3 c 為 1,2,3,4,5 [:] 表示 [0:len(a)], 第一個值如果沒寫則為 0, 第二個沒寫的為 len(a) = 5
  • 41. Golang 入門初體驗 Go 語法 Slice 所以可以得知 a[:3] 和 a[1:] 個別為 1,2,3 //a[:3] 2,3,4,5 //a[1:] 另外要特別注意的是, b := a[1:3] 並不是 a copy 值給 b, 而是將 b 的指標指向 a ( index 2 ) 的位置 所以這表示如果你改了 b 的值, a 的也會一起改變, 因為他們共用同一個 array. 如果你要兩者是獨立的, 可以使用 copy 的方法 copy(b,c)
  • 42. Golang 入門初體驗 Go 語法 Slice 這是把 c 的前兩個的值, copy 到 b 中. 為什麼只 copy c 的前兩個?因為 b 的大小只有二, 以小的為主 copy(c,b) 則表示將 b 的值, copy 覆蓋 c 的前兩個值. 另外可以用 append 來增加他的大小 如下所示 import "fmt" func main(){ var a[]int a = append(a,1) a = append(a,2) for i := range a { fmt.Println(a[i]) } }
  • 43. Golang 入門初體驗 Go 語法 Map 建立一個 map 可以用以下兩種方式 m := make(map[string]int) m := map[string]int{} 定義 age = 16 m["age"] = 16 回傳值, 和 map 是否存在 value , ok := m["age"] 如果是不存在的 key , value = 0 , ok = false value , ok := m["height"]
  • 44. Golang 入門初體驗 Go 語法 Map 利用 rage 取得 map 中所有的 key 和 value, 並列印 for key, value := range m { fmt.Println("Key:", key, "Value:", value) } 如果要一次宣告多個值, 可以用以下方式 person := map[string]int{ "age" : 16, "height" : 180, "weight" : 6, } https://play.golang.org/p/rPpLGhc9lE
  • 45. Golang 入門初體驗 Go 語法 Goroutine 在講goroutine之前, 必須先了解 concurrency 和 parllelism的不同 concurrency (併發) vs parallelism (並行) 併發 concurrency 是將 process 切割成多個可執行單位(coroutine), 如果有多個 process 時則在 coroutine 中 交互執行, 這樣不會因為某一個 process 執行太久造成其他 process 無法處理, 會讓你有多工的感覺. 但這並不 會增加執行效率. 總執行時間是一樣的, 如圖一所示. 另外和 thread 不同的是, thread 是屬於 os 層面上的, 且 thread 非常消耗系統資源.
  • 47. Golang 入門初體驗 Go 語法 Goroutine 並行 parallelism 是多個 process 由多個 cpu 去執行, 可以增加執行的效率, 縮短總執行的時間. 如圖二所示
  • 48. Golang 入門初體驗 Go 語法 Goroutine go 用 goroutine 實現了 concurrency. 使用者只要設定最大的 thread 數量, 和系統是多少CPU, run-time 就會 幫你處理好剩下的 thread 管理, 但為什麼 gorountine 可以提供較好的效能? (以下為個人心得可能有錯)
  • 49. Golang 入門初體驗 Go 語法 Goroutine 第一. 在創造 goroutine 的資源消耗是很小的, 因為 goroutine 只是一個 function 的入口. 只要很小的 stack 去 記錄即可. 第二. thread 上的管理, 當某個 goroutine 被 block 住, 處理此 goroutine 的 thread 就耗在這上, 此時 run-time 會將其他的 goroutine 轉給此 thread 去執行, 這樣 thread 就不會因為執行某些被 block 的任務則消耗在那邊. 有效的使用 thread. 第三. thread 最多不會超過 $GOMAXPROCS(使用者設定的), 可以確保 thread 不會失控的增加. 綜合以上三點, goroutine 其實就是避免 thread 的不當增加, 有效的使用目前的 thread , 這樣系統資源的消耗就 少了. 不會因為系統的資源不夠造成整體效能的降低. coroutine 資料一 coroutine 資料二 thread 資料 goroutine 資料一 goroutine 資料二 goroutine 資料三
  • 50. Golang 入門初體驗 Go 語法 goroutine - channels Don't communicate by sharing memory; share memory by communicating. 不同於過去的 muliti thread 的程式開發, 常使用共用變數去做資訊傳遞 (communicate by sharing memory). goroutine 彼此的溝通方式是使用 channel (share memory by communicating). 這樣的方式會讓整個流程在 表現上變得清楚. channels channel 的通訊, 需要一個 sender 和一個 receiver, 當 sender 和 receiver 都 ready 時候, 訊息才會成功的傳遞. import "fmt" func main(){ s := mack(chan string) //宣告一個 channel 變數 s <- "hello" //寫入 channel (sender) val <- s //讀取 channel (receiver) fmt.Println(val) } 上例說明了如何宣告 channel 變數, 寫入 channel, 讀取 channel.
  • 51. Golang 入門初體驗 Go 語法 goroutine - channels 但是 code 無法跑, compiler 會顯示 dead lock. 因為執行到 s <- "hello" 這步的時候, sender 就會進入 ready 狀態. 然後就停住了, 也就是他不會執行到 val := <- s . 這時我們建立一個 goroutine 去跑 s <- "hello" import "fmt" func main(){ s := make(chan string) //宣告一個 channel 變數 go func(){ s <- "hello" //寫入 channel (sender) }() val := <- s //讀取 channel (receiver) fmt.Println(val) }
  • 52. Golang 入門初體驗 Go 語法 goroutine - channels 執行順序就是 1. 建立一個 goroutine //此時 s <- "hello" 還沒執行 2. 執行 val := <- s //s 空的, receiver ready (停住) 3. 執行 s <- "hello" //sender 將訊息寫入 s, sender ready 4. val := <- s //成功讀取 s, (因為 receiver, sender 都 ready) 5. fmt.Println(val) goroutine 不見得會比較慢執行. 不過重點不在這, 就不多描述了. 所以要看執行的順序就要注意這原則 "當 sender 和 receiver 都 ready 時候, 訊息才會成功的傳遞. " 再舉一個例子, 請問順序式如何?
  • 53. Golang 入門初體驗 Go 語法 goroutine – channels import "fmt" func main(){ s := make(chan string) go func() { for i := 0; i < 3; i++ { fmt.Println("sender hello",i) s <- fmt.Sprintf("receiver hello %d", i) } }() for i := 0; i < 3; i++ { val := <-s fmt.Println(val) } }
  • 54. Golang 入門初體驗 Go 語法 goroutine – channels 結果 sender hello 0 sender hello 1 receiver hello 0 receiver hello 1 sender hello 2 receiver hello 2 有對嗎?程式碼順序是這樣 1. 建立一個 goroutine 2. 執行 val := <- s //s 空的, receiver ready (停住) [sender hello 0] 3. 執行 s <- fmt.Sprintf.. //sender 將訊息寫入 s, 傳訊成功 [sender hello 1] 4. 執行 s <- fmt.Sprintf.. //s 有值, sender ready(停住) 5. val := <-s //讀到 s 的值 [receiver hello 0] 6. val := <-s //s 空的, receiver ready, 傳訊成功 [receiver hello 1] 7. val := <-s //s 空的, receiver ready (停住) [sender hello 2] 8. 執行 s <- fmt.Sprintf.. //sender 將訊息寫入 s, 傳訊成功 9. val := <-s //讀到 s 的值 [sender hello 2] http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
  • 55. Golang 入門初體驗 Go 語法 goroutine – channels 另外我們可以修改 channel 的大小為 2 import "fmt" func main(){ s := make(chan string,2) go func() { for i := 0; i < 3; i++ { fmt.Println("sender hello",i) s <- fmt.Sprintf("receiver hello %d", i) } }() for i := 0; i < 3; i++ { val := <-s fmt.Println(val) } } 結果 sender hello 0 sender hello 1 sender hello 2 receiver hello 0 receiver hello 1 receiver hello 2 http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
  • 56. Golang 入門初體驗 Go 語法 defer panic recover defer 先看以下範例 func f(){ for i := 0 ; i < 5 ; i++{ fmt.Println(i) } fmt.Println("f finish") } 此時的結果是 0 1 2 3 4 f finish
  • 57. Golang 入門初體驗 Go 語法 defer panic recover 如果再 fmt.Println 前面加上 defer func f(){ for i := 0 ; i < 5 ; i++{ defer fmt.Println(i) } fmt.Println("f finish") } 結果就變成 f finish 4 3 2 1 0
  • 58. Golang 入門初體驗 Go 語法 defer panic recover defer 是讓 fmt.Println(0) , fmt.Println(1) , fmt.Println(2) , fmt.Println(3) , fmt.Println(4) 依序放到清單中, 等到 func f 結束前, 再依據 Last-In-First-Out (LIFO) 的順序 call 清單中的 function. 這樣功能提供了什麼的好處? 我們再看以下的例子
  • 59. Golang 入門初體驗 Go 語法 defer panic recover func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } dst, err := os.Create(dstName) if err != nil { return } written, err = io.Copy(dst, src) dst.Close() src.Close() return }
  • 60. Golang 入門初體驗 Go 語法 defer panic recover 這個例子有個 bug, 就是當 os.Create(dstName) 失敗的時候 function 就會 return, 而 src.Close() 就沒有執行 到了. 所以可以改成這樣
  • 61. Golang 入門初體驗 Go 語法 defer panic recover func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } dst, err := os.Create(dstName) if err != nil { src.Close() return } written, err = io.Copy(dst, src) dst.Close() src.Close() return }
  • 62. Golang 入門初體驗 Go 語法 defer panic recover 但是如果開多個檔案? 那會很麻煩 所以我們利用 defer 來修改 func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src) } 這時不管如何, 都會執行 close function.
  • 63. Golang 入門初體驗 Go 語法 defer panic recover 但是如果開多個檔案? 那會很麻煩 所以我們利用 defer 來修改 func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src) } 這時不管如何, 都會執行 close function. 參考網站 https://blog.golang.org/defer-panic-and-recover panic recover go 沒有 try catch , 原因是 go 的開發者認為, 當過多 try catch 時 會造成程式碼很難閱讀. 所以提供了 panic recover 優雅的解決這 個問題.
  • 64. Golang 入門初體驗 Go 後續 GoWeb Go Bot (Line、Facebook Message、Slack、Telegram、 ……..) Go 機器學習 Go 物聯網