[Golang][程式設計週記].. 2015第八週

##雜七雜八感言:

本週工作三天… 把一些春節沒看的文章看了一下.Golang 的新聞也似乎春節後開始變多….. BTW我也開始維護自己的一份pocket list,主要會放在這裡

##筆記:

Cutting-edge Web Technologies 網路課程

想要有系統的了解最新 Web Technologies 的人可以看看 Berkeley 開的 Cutting-edge Web Technologies 課程,slide 跟錄影都會放出來!

[Golang] 關於Golang 有趣的網頁與小工具

[Golang] GoPanic

Panic 是Go裡面一個發生錯誤會呼叫的函式,其實只是做memory dump而以.但是為了避免Panic 發生的時候,一些資料被竊取.

Cold Boot Attack:

原本指的是加密的key寫在記憶體,卻被冷卻後移除電腦而直接讀取記憶體中的ram.也就是一種資料竊取的手法,而在網路裡面就是指發生panic的時候,卻從dump資料或是處理到一半的資料竊取到有加密的資料.

所以GoPanic 做的事情相當簡單:

  • 建立一個UDP services
  • 當系統呼叫propietary panic function (ex: do_panic() ),就會呼叫這個 UDP services 去做某些事情.(可能是關閉services或是清除暫存資料…等等)
  • do_panic裡頭呼叫的處理部分需要自己處理.

這個部分可以參考 Python 的[panic_bcast](https://github.com/qnrq/panic_bcast

[Golang][程式設計週記].. 2015第六週

##雜七雜八感言:

最近工作都在弄Go的Server,應該之後會把心得整理一下. 發現用Go 來處理網路的相關封包,其實相當的方便又好用啊.

##筆記:

###[Golang] 一些有趣的package 跟 網站

###[Golang] 關於JSONRPC 心得筆記

利用JSONRPC package 可以很快速地建立一個JSON RPC Server/Client架構. 這裏有一個簡單的example可以參考,主要要注意的事情如下:

  • API為兩個參數,一個Input 一個Output.還有回傳值err. 要注意, Output使用point,相關的數值處理小心忘記指標與數值的關係.
  • 由於使用JSON,在Client這邊的回傳值個數可以多或是少. 不會影響結果,只要注意操作就好.
  • 如果error 不為空的時候,千萬注意 output會被清掉. 這個是經過很多次失敗後,跑回去看src才知道是故意的.

Refer Golang pkg source /net/rpc/jsonrpc/server.go

  
  resp := serverResponse{Id: b}
  if r.Error == "" {
  // 只有在 Error == nil 才會傳Return 的Interface..
 	resp.Result = x
  } else {
  	resp.Error = r.Error
  }
  return c.enc.Encode(resp)

###[Golang] 關於Go init()

看到有人提到的有趣部分,也發現自己沒有那麼注意到這一塊. 主要問題來自於這個stack overflow

defined in its source. A package-scope or file-scope identifier with name init may only be declared to be a function with this signature. Multiple such functions may be defined, even within a single source file; they execute in unspecified order.

簡單的來說, func init()在一個檔案裡面會最早被呼叫到.但是不僅僅可以存在唯一個,他可以存在多數個的,並且正常運作. 而呼叫的順序會依照line order來排序,在前面的會先跑到.

  
package main

import "fmt"

func init() {
	fmt.Println("Run first")
}

func init() {
	fmt.Println("Run second")
}

func main() {

	fmt.Println("Hello, playground")
	
}

Go Plau is here

[Golang]Study note about 'Taking Out The Trash talk'

image

What is this talk about

Here is the talke Taking Out the Trash: Great talk about optimizing memory allocation. about Go memory optimize and GC.

I have read it, and note my understanding as follow:

##Note:

###How does Go allocate / deallocate memory?

  • Use stack for local variable and cleanup when return.
  • Use heap when large local variale or compiler cannot approve are not referenced. It cleanup by GC.
  • More detail in golangDoc- stack or heap

Reserving Virtual Memmory

  • Golang will reserve the virtual memory but not use it. If you want to know how much memory use by go need check “top” (check RES/RESIZE columns).

image

(Refer to Dave Cheney:Visualising the Go garbage collector, you can see the system memory will not return by Go)

When GC Run?

  • Base on source code src/runtime/mgc0.c define the GOGC environment is 100. We could adjust it to change to GC period.
  • The more gabarge you make, means it need run more times of GC.

Reuse your slice

Slice address will create and reserve once you use it, if some slice you will not use it anymore. We could recycle its address to reduce memory allocate time and reuse memory by GC.

 
package main

import "fmt"

func main() {
	a := []string{"Hello", "World"}
	//a=["Hello", "World"]

	b := a[:0]
	//b=[] but cap and address is the same with a

	fmt.Println(a, b, cap(a), cap(b), len(a), len(b))
	//[Hello World] [] 2 2 2 0
	//*note* The cap is the same, but length is different.

	b = append(b, "Change")
	//Appen one item to b, it will also change a because they share the same address.

	fmt.Printf("a content=%q, b content=%s, length(a)=%d, length(b)=%d, address(a)=%d, address(b)=%d\n", a, b, len(a), len(b), &a[0], &b[0])
	//a content=["Change" "World"], b content=[Change], length(a)=2, length(b)=1, address(a)=272851328, address(b)=272851328
}

Play is here.

For slice resource allocation, we could refer to slice trick in Golang wiki.

[Golang]關於 Channels 的控制一些要注意的事項(一)

image

前言

學習Golang 讓人最興奮的大概就是它內建的 Concurrency 的支援,並且相當的容易使用. 但是最近在學習與使用的時候,發現發現 Goroutine 可以讓本來需要用到 40 秒的 Request 減少到1/3 左右的時間.進而可以進步到 5 秒左右.平常的應用上,幾乎已經離不開 Goroutine 與Channel。

但是最近遇到幾個例子,一開始覺得很不能理解,也不容易解決.也是讓我找了一些解決方式.

一般用法

Go Channel一般有兩種用法(當然有更多的使用方式可以用),一個是把channel當成資料來傳遞,另外的方式只是單純把channel當成是signal來等待或是啟動新的thread

  
// 同時要處理多個可以同步運行的運算,利用channel來回傳結果
c := make(chan int)  // Allocate a channel.
go func() {
    result : = do_some_cal()
    c <- result
}()

c2 := make(chan int)  // Allocate a channel.
go func() {
    result : = do_some_cal2()
    c2 <- result
}()

totalResult := <-c2 + <-c
fmt.Printf("result is %d"), totalResult)   


// 傳送訊號(signal)的方式
c := make(chan int)  // Allocate a channel.
go func() {
    list.Sort()
    c <- 1  // Send a signal; value does not matter.
}()
doSomethingForAWhile()
<-c   // Wait for sort to finish; discard sent value.

陷阱出現了

以上兩個方式相當的簡單,也相當直覺來使用.但是如果要跑goroutine的條件不是必要呢?也就是說不一定要透過go routine來同步執行很多的結果呢?

  
c := make(chan int)  

//並不一定會進入go routine來計算,也就是說channel會是為空的.
if needRoutine == true {
    go func() {
        result : = do_some_cal()
        c <- result
    }()
} else {
    c <- 0 //note this kind will not work, because channels need input value in go routine.
}

// 這裏將會變成deadlock,而無窮的等待.
totalResult := <-c * 3 + 5
fmt.Printf("result is %d"), totalResult)   

上面的例子可以看到,當needRoutine為false的時候,由於不會去跑go routine,所以 <-c會變成是deadlock.

此外,如果你試著在else 的地方自己加上 c <- 0,也是沒有任何作用.

所以尋找過後,有一些解決的方式可以參考.

解決方式

由邏輯來解決

比較簡單方式,並且code上面比較不會那麼複雜的方式是.就是在Go routine裡面去做額外的處理.也就是都會進去Go routine而在Go routine中再做檢查而回傳.

  
c := make(chan int)  

go func() {
     //在Go Routine中處理
     if needRoutine == false {
        c <- 0 //or other invalid value
        return
     }
     result : = do_some_cal()
     c <- result
}()

// 這樣就不會變成無窮等待
result := <-c
if result > 0 {
   totalResult := result * 3 + 5
   fmt.Printf("result is %d"), totalResult)   
}

透過selector

透過Selector其實可以處理的事情相當的多. 它不僅僅可以分派處理很多個需求,先講解一些方式.

透過timer

透過時間檢查, 過了特定時間就放棄不等. 這種解法比較好,只要在特定時間內如果能收到數值,即時還是可以順利得到結果.

  
package main

import "time"
import "fmt"

func main() {

    c1 := make(chan string, 1)
    go func() {
        time.Sleep(time.Second * 2)
        c1 <- "result 1"
    }()
    
    select {
    case res := <-c1:
        fmt.Println(res)
    case <-time.After(time.Second * 1):
        fmt.Println("timeout 1")
    }
}
透過檢查channel有沒有設定過

以下例子可以檢查,如果channel有沒有設定過,才決定要不要拿來用. 不過這種狀況下,如果你的Goroutine需要一點時間無法馬上傳回解答的時候,這個時候就會馬上離開.

所以,如果原本到這個時候就應該有解答(不需要任何等待(non block)),可以使用這種方式.不然的話還是建議使用timer的方式.

  
package main

import "time"
import "fmt"

func main() {

    c1 := make(chan string, 1)
    
    if someCondition == true {     
        go func() {
            time.Sleep(time.Second * 2)
            c1 <- "result 1"
        }()
    }

   select {
    case x, ok := <-c1:  //如果someCondition == true 除非這時候剛好得到結果,不然跑不到.
        if ok {
            fmt.Printf("Value %d was read.\n", x)
        } else {
            fmt.Println("Channel closed!") //Channel 被close.
        }
    default:
        fmt.Println("No value ready, moving on.") //Channel 沒有設定過,會馬上離開....
    }
}

Refer here.

進階的用法

這裏附上另外一個select的用法,就是來取得多個channel的資料.並且也用一個timer來顯示時間經過了幾秒. 全部做完才會離開…. 不然就是超過一定時間也會離開,避免有dealock產生.

  
package main

import "time"
import "fmt"

func main() {

	c1 := make(chan string, 1)
	
	someCondition := true
	if someCondition == true {
		go func() {
			time.Sleep(time.Second * 4)
			c1 <- "result 1"
		}()
	}
	
	c2 := make(chan string, 1)
	if someCondition == true {
		go func() {
		    //故意延遲九秒,所以這個不會順利結束.
			time.Sleep(time.Second * 9)
			c2 <- "result 1"
		}()
	}
	
	doneCount := 0
	allDone := 2
	timeCount := 0
	
	// 別忘了... select 滿足任何一個都會離開,所以要有個for在外面讓他不停跑
	for doneCount < allDone && timeCount < 5 {
	
		select {
		//檢查C1
		case x, ok := <-c1:
			if ok {
				fmt.Printf("C1 in valus is %s.\n", x)
				doneCount++
			} else {
				fmt.Println("Channel closed!") //Channel 被close.
			}
		//檢查C2
		case x, _ := <-c2:
			fmt.Printf("C2 in valus is %s.\n", x)
			doneCount++
	
	    //另外準備一個離開條件,當五秒會離開...
		case <-time.After(time.Second * 1):
			fmt.Println("tick..")
			timeCount++
	
		}
	}
}

Go Play code is here

回過頭來看.. channel buffer..

關於channel沒經過goroutine會出問題的原因,經過尋找過後總算找到原因了. 可以參考以下這篇文章

By default channels are unbuffered, meaning that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) ready to receive the sent value.  (from [Go Example](https://gobyexample.com/channel-buffering))

也就是說,如果你沒有幫channel 設定好buffer (也就是 make(chan int, 1))先給他個預設空間的話. channel <- value 會一直等到…. <- channel 才會順利結束. 這也是如果你直接使用channel 而沒有進入goroutine或是給予buffer就會deadlock

  
package main

import "fmt"

func main() {

	messages := make(chan string)
	
	messages <- "buffered" //會有deadlock,因為會停到直到跑到 <-messages
	messages <- "channel"  //會有deadlock,因為會停到直到跑到 <-messages
	
	fmt.Println(<-messages)
	fmt.Println(<-messages)
}

正確的解法,就是要給予channel buffer

  

package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan int, 1) //Add buffer cause not deadlock. http://stackoverflow.com/questions/14050673/why-are-my-channels-deadlocking
	needRoutine := false

	if needRoutine {
		go func() {
			time.Sleep(time.Second * 3)
			c <- 3
		}()
	
	} else {
		c <- 0
	}
	
	totalResult := <-c*3 + 5
	
	fmt.Printf("result is %d", totalResult)
}

Go play is here

參考資料

[Golang][程式設計週記].. 2015第五週

image

##雜七雜八感言:

令人開心的事情,總算在工作上把某些專案推坑Golang… 可以更專心的學習跟使用Golang…

##筆記:

###[Golang] 一些有趣的package 跟 網站

  • [Golang][Gala] Final list of Gala
    • 最後進入final 名單的Gala 2015競爭者,Docket竟然被踢掉了…
  • [Golang][Gala] http://gophergala.com/blog/gopher/gala/2015/02/03/winners/
    • 最後的獲勝者出線了….
  • [Golang]Go Report Card: A report card for your Go application
    • 根據你github上面的go project給予一些分數,評分依據根據gofmt, go vet, go lint與 gocyclo.
    • 挺有趣的,很多時候issue越多並不代表分數不高喔…
  • [Golang] Beego 的教學(tutorial)
    • First,Second, Third, Git
    • 這是之前又介紹過MVC架構的Web Framework Beego的教學.Beego被許多大公司所使用(Weibo, Taobao, Tudou….),算是很棒的架構,有機會可以好好學習.
  • [Golang]Moving from Node.js to Go at Bowery
    • Bowery這家公司把他們平台從Node.js換到Go的經歷.裡面有提到以下的優點:
      • Easy to write cross-platform code, Faster deployment, Concurrency primitives, Integrated testing framework, Standard library and Developer workflow tools are more powerful.
  • [Golang] Go HTTP request router benchmark and comparison
    • 有各種Go Webframework的效能比較,幾個值得注意的事情是net/http 的ServerMux並不會有最好的效能.而martini雖然效能最差,但是擴展性是最高的.
    • 也可以順便知道有多少web framework…. (Beego, go-json-rest, Denco, Gocraft Web, Goji, Gorilla Mux, http.ServeMux, HttpRouter, HttpTreeMux, Kocha-urlrouter, Martini, Pat, TigerTonic, Traffic)
  • [Livehouse.in] 關於c9s的slideshare “Get Merge!”
  • [Golang] Sample Email Sender using SocketLabs
    • 不錯的寄信範例程式使用Go

[Golang] 關於Session的學習

要開始弄martini關於authorication的部分,首先最簡單的除了SSL之外,就使用session了. Martini session 提供了一個相當簡單的方式來使用.

首先可以參考這段教學影片,其實相當的簡單易用,也可以設定哪些網址才需要透過session.

[Golang] 關於Go與CGI的搭配

本來的討論是希望讓Go可以取代PHP在Apache中的地位,主要可以達成以下的結果:

  • 可以多個process,彼此獨立
  • 一個process 出事情不會影響到全部的系統.

是開始尋找有沒有類似的結果,如下:

其他相關的問與答在這裡翻到的:

[Golang] 關於Go來實現RPC相關研究

一但決定要用Go來當成Services,這時候其實有不少solution可以使用.不過要使用哪一種的方式可能有許多可以學習.

先決定使用Golang的RPC的,參考這裡的部分可以先完成第一個部分的RPC Go Server 與 Go Client. 如果要適用RPC Go Server的話,由於他的資料傳遞都有透過gob來marshall過.所以一般其他語言要呼叫的話,是無法直接連接的. 這裏所以如果要其他語言(比如C)要連接Go RPC Server,比較建議使用libgob

所以如果要去除gob造成的影響,另外一個方式是換成JSONRPC.不過差異就是,原先RPC 使用的是Http在Go 裡面,而改成JSONRPC就會變成是Web Socket.要修改成HTTS 上面變得比較困難. 但是其實還是有Gorilla 可以使用.

[Golang] 關於可變參數的傳遞…

主要是想要做出類似以下方式,可以直接將可變參數直接傳下去.

  
func foo(arg ...) {
    fooCall(arg)
}

fooCall(arg ....) {
}

查詢到這篇文章,裡面Russ Cox(Golang開發團隊之一)有提到似乎只能有partial re-warpping.

  
//There's no language mechanism for this, nor is there a Vsprintf func.
//The special case that avoids re-wrapping arguments is tied to 
//the parameter itself, not the type system.  But you can fake it:

	package main
	
	import "fmt"
	
	func vsprintf(f string, args []interface{}, dummy ...interface{}) string {
		dummy = args
		return fmt.Sprintf(f, dummy)
	}
	
	func sprint(f string, arg interface{}) string {
		return vsprintf(f, []interface{}{arg})
	}
	
	func main() {
		fmt.Println(sprint("%d", 5))
	}

//It's hardly elegant, but it works, and the need is rare.
//Russ

code here

[Other] RPI(Raspberry Pi 2.0) 2.0 出來了

這個禮拜比較大的新聞,大概就屬RPI 2.0的規格正式出來,有一倍的記憶體跟六倍的速度,並且可以安裝Windows10

不過我自己還是主要把RPI當作XBMC的多媒體播放器來使用,不過這段影片有把RPI當成任天堂來使用,到也是蠻特別的.

個人覺得有可能的未來如下:

  • 耗電量,應該完全不是走IOT的部分,比較可能是小型電腦與小型伺服器的走向.
  • 由於可以安裝Windows 10,代表著可能性又變得更高,可以朝向家裡的中控中心來思考.或是Cortana的中心.

[Golang][程式設計週記].. 2015第四週

##雜七雜八感言:

啊… 我覺得我blog樣板好醜啊….應該要改成Patrick類似的… 本來想加回廣告的… 後來看到每天流量沒有破百…. 算了….

##筆記:

以下是關於本週的學習筆記…

###[Golang] 一些有趣的package 跟 網站

[Golang] “Beego” Framework: An open source framework to build and develop your applications in the Go way

image

[Golang] Concurrency 實戰初體驗-

  • 一開始學習都Go Routine都是寫一些簡單的程式,最近有機會應用到網站上面的時候,有一些簡單的心得.也順便把所有的Godoc仔細地查看了一下.
  • 使用時機:
    • 需要他的回傳值或是修改後的結果,使用Channel
    • 不需要,就直接使用Goroutines
    • goroutines如果有太多參數要使用,直接寫成在func裡面.
  • 使用成效:
    • 一個需要用到對照查詢的部分,原本要40s可以節省到1/3(甚至更少..).
  

// 一個effective_go 上透過channel完成類似message queue的概念
var sem = make(chan int, MaxOutstanding) //MaxOutstanding 最多可執行的thread數

func handle(r *Request) {
    // sem在這邊只是作為MaxOutstanding的個數參考,如果超過MaxOutstanding就無法指定新的數值
    sem <- 1    // Wait for active queue to drain.
    process(r)  // May take a long time.
    <-sem       // Done; enable next request to run.
}

func Serve(queue chan *Request) {
    for {
        //等待新的message(request)進來
        req := <-queue
        go handle(req)  // Don't wait for handle to finish.
    }
}

[RPI+node.js]自己的 Dropcam 自己 Make

  • 有人把自己整套dropcam的solution 包含伺服器與RPI上面client的code都分享出來.並且透過deploy to heroku這個按鈕,可以一鍵部署到heroku去.
  • 完整source code在這裡image

[Cloud Load Testing]關於負載測試的服務與提供

  • 主要是由Azure看到的服務介紹,來瞭解到原來雲端負載測試是可以外包給雲端服務的.不過考量到伺服器的測試會造成許多額外得費用.這部分想玩還要找時機啊.
  • Blitz另外一家雲端負載測試公司
  • Loadstorm 這也是另外一家….

[Other] 雜七雜八的鏈結

[Code Style] Python Google Code Style