2016-06-13 62 views
2

我想在另一個goroutine中運行一些日常緩慢運行,是安全的做這樣的:網絡掛接程序上的另一個夠程

func someHandler(w http.ResponseWriter, r *http.Request) { 
    go someReallySlowFunction() // sending mail or something slow 
    fmt.Fprintf(w,"Mail will be delivered shortly..") 
} 

func otherHandler(w http.ResponseWriter, r *http.Request) { 
    foo := int64(0) 
    bar := func() { 
     // do slow things with foo 
    } 
    go bar() 
    fmt.Fprintf(w,"Mail will be delivered shortly..") 
} 

有沒有做這個任何陷阱?

回答

4

爲每個http請求提供服務運行在其自己的goroutine(more details on this)中。您可以從您的處理程序啓動新的goroutine,並且它們將同時運行,與執行處理程序的goroutine無關。

有些事情看出來:

  • 新的goroutine獨立於處理器夠程運行。這意味着它可能在處理程序goroutine之前或之後完成,如果沒有明確的同步,你不能(不應該)假定任何有關此的任何事情。

  • http.ResponseWriterhttp.Request處理程序的參數只有有效和安全使用,直到處理程序返回!這些值(或它們的「部分」)可以被重用 - 這是一個實現細節,你也不應該假設任何東西。一旦處理程序返回,您不應該觸摸(甚至不讀取)這些值。

  • 處理程序返回後,響應被提交(或可能在任何時刻提交)。這意味着在此之後,您的新goroutine不應該嘗試使用http.ResponseWriter發回任何數據。即使您的處理程序中沒有觸摸http.ResponseWriter,也不會觸發處理程序的panicing,因爲這是對該請求的成功處理,因此會發回HTTP 200狀態(see an example of this)。

你被允許到http.Requesthttp.ResponseWriter值傳遞給其他的功能和新的夠程,但必須注意:你應該使用明確的同步(如鎖,通道)如果你打算讀/修改這些來自多個goroutine的值(或者您想要從多個goroutine發回數據)。

請注意,看起來如果您的處理程序goroutine和您的新goroutine只是讀取/檢查http.Request,那仍然可能有問題。是的,多個goroutines可以在沒有同步的情況下讀取同一個變量(如果沒有人修改它)。但是調用http.Request的某些方法也會修改http.Request,如果沒有同步,則不能保證其他goroutine會從這種更改中看到什麼。例如Request.FormValue()返回與給定密鑰關聯的表單值。但是,如果需要修改http.Request(例如,它們設置了Request.PostFormRequest.Form結構字段),則此方法調用ParseMultiPartForm()ParseForm()

所以,除非你同步夠程,你不應該通過RequestResponseWriter新夠程,但獲得來自於處理器的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可見) - 但無論如何這需要同步,這將被通道取代解)。

1

如果您關心郵件的確認,那麼發佈的代碼將無濟於事。在單獨的goroutine中運行代碼使其獨立,即使由於goroutine函數中的某些錯誤而未發送郵件,服務器應答也會成功。