Http Webhook进程在另一个goroutine上运行
我想在另一个goroutine中运行一些缓慢的例程,这样做安全吗:Http Webhook进程在另一个goroutine上运行,http,go,server,goroutine,Http,Go,Server,Goroutine,我想在另一个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.ResponseWri
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..")
}
foo := int64(0)
bar := func(foo int64) {
// do slow things with param foo (not the local foo var)
}
go bar(foo)
这样做有什么问题吗?如果你想确认邮件,那么发布的代码就没有帮助了。在单独的goroutine中运行代码将使其独立,即使由于goroutine函数中的某些错误而未发送邮件,服务器回复也将成功。为每个http请求提供服务将在其自己的goroutine()中运行。您可以从处理程序启动新的goroutine,它们将并发运行,独立于执行处理程序的goroutine 有些事情需要注意:
- 新的goroutine独立于处理程序goroutine运行。这意味着它可能在处理程序goroutine之前或之后完成,在没有显式同步的情况下,您不能(不应该)假设与此相关的任何事情
- 处理程序的和参数仅在处理程序返回之前有效且安全!这些值(或其中的“部分”)可以重用——这是一个实现细节,您也不应该假设任何东西。一旦处理程序返回,您就不应该触摸(甚至不读取)这些值
- 一旦处理程序返回,响应就被提交(或者可以在任何时刻提交)。这意味着您的新goroutine在此之后不应尝试使用
发回任何数据。这在某种程度上是正确的,即使您不触摸处理程序中的http.ResponseWriter
,从处理程序中不惊慌也被视为成功处理了请求,因此http 200状态被发回()http.ResponseWriter
http.Request
和http.ResponseWriter
值传递给其他函数和新的goroutine,但必须注意:如果您打算从多个goroutine读取/修改这些值,则应使用显式同步(例如锁、通道)(或者您希望从多个goroutine发回数据)
请注意,如果处理程序goroutine和新goroutine都只是读取/检查http.Request
,这可能仍然有问题。是的,多个goroutine可以在不同步的情况下读取同一变量(如果没有人修改它)。但是调用http.Request
的某些方法也会修改http.Request
,如果不进行同步,则无法保证其他goroutine会从该更改中看到什么。例如,返回与给定键关联的表单值。但是此方法调用和(如果需要)修改http.Request
(例如,他们设置和Request.PostForm
struct字段) 因此,除非同步您的goroutine,否则您不应该将Request.Form
和请求
传递给新的goroutine,而是从处理程序goroutine中的响应编写器
中获取所需的数据,并且只传递例如保存所需数据的请求
结构 你的第二个例子:
这很好,这是一个函数,它所引用的局部变量只要可以访问,就可以继续存在 请注意,也可以将局部变量的值作为参数传递给匿名函数调用,如下所示:foo := int64(0) bar := func() { // do slow things with foo } go bar()
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..") }
在本例中,匿名函数将看到并使用其参数foo := int64(0) bar := func(foo int64) { // do slow things with param foo (not the local foo var) } go bar(foo)
,而不是局部变量foo
。这可能是您想要的,也可能不是您想要的(取决于处理程序是否也使用foo
,以及任何goroutine所做的更改是否需要对另一方可见-但这无论如何都需要同步,而同步将被通道解决方案所取代)foo