爲每個http請求提供服務運行在其自己的goroutine(more details on this)中。您可以從您的處理程序啓動新的goroutine,並且它們將同時運行,與執行處理程序的goroutine無關。
有些事情看出來:
新的goroutine獨立於處理器夠程運行。這意味着它可能在處理程序goroutine之前或之後完成,如果沒有明確的同步,你不能(不應該)假定任何有關此的任何事情。
該http.ResponseWriter
和http.Request
處理程序的參數只有有效和安全使用,直到處理程序返回!這些值(或它們的「部分」)可以被重用 - 這是一個實現細節,你也不應該假設任何東西。一旦處理程序返回,您不應該觸摸(甚至不讀取)這些值。
處理程序返回後,響應被提交(或可能在任何時刻提交)。這意味着在此之後,您的新goroutine不應該嘗試使用http.ResponseWriter
發回任何數據。即使您的處理程序中沒有觸摸http.ResponseWriter
,也不會觸發處理程序的panicing,因爲這是對該請求的成功處理,因此會發回HTTP 200狀態(see an example of this)。
你被允許到http.Request
和http.ResponseWriter
值傳遞給其他的功能和新的夠程,但必須注意:你應該使用明確的同步(如鎖,通道)如果你打算讀/修改這些來自多個goroutine的值(或者您想要從多個goroutine發回數據)。
請注意,看起來如果您的處理程序goroutine和您的新goroutine只是讀取/檢查http.Request
,那仍然可能有問題。是的,多個goroutines可以在沒有同步的情況下讀取同一個變量(如果沒有人修改它)。但是調用http.Request
的某些方法也會修改http.Request
,如果沒有同步,則不能保證其他goroutine會從這種更改中看到什麼。例如Request.FormValue()
返回與給定密鑰關聯的表單值。但是,如果需要修改http.Request
(例如,它們設置了Request.PostForm
和Request.Form
結構字段),則此方法調用ParseMultiPartForm()
和ParseForm()
。
所以,除非你同步夠程,你不應該通過Request
和ResponseWriter
新夠程,但獲得來自於處理器的goroutine的Request
所需的數據,並通過例如只一個持有所需數據的struct
。
你的第二個例子:
foo := int64(0)
bar := func() {
// do slow things with foo
}
go bar()
這是完全正常的。這是一個closure,由它引用的局部變量只要可訪問就會存活。
注意,或者你可以在局部變量的值傳遞給匿名函數調用時,像這樣的說法:
foo := int64(0)
bar := func(foo int64) {
// do slow things with param foo (not the local foo var)
}
go bar(foo)
在這個例子中,匿名函數將看到和使用它的參數foo
,而不是局部變量foo
。這可能是也可能不是你想要的(取決於處理程序是否也使用foo
以及任何一個goroutine所做的更改是否需要對另一個goroutine可見) - 但無論如何這需要同步,這將被通道取代解)。