我想在另一个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..")
}
这样做有什么陷阱吗?
服务每个http请求都在其自己的goroutine中运行。您可以从处理程序中启动新的goroutine,它们将并发运行,与执行处理程序的goroutine独立。
要注意的一些事情:
新的goroutine与处理程序goroutine独立运行。这意味着它可能在处理程序goroutine之前或之后完成,如果没有显式同步,则不能(不应)对此进行任何假设。
处理程序的http.ResponseWriter
和http.Request
参数只有在处理程序返回之前才有效且可以安全使用!这些值(或其中的“部分”)可以重复使用-这是一个实现细节,您也不应假设任何事情。处理程序返回后,您不应触摸(甚至不读取)这些值。
处理程序返回后,将提交响应(或者可以随时提交响应)。这意味着您的新goroutine不应尝试使用http.ResponseWriter
after之后发送回任何数据。即使您没有触摸http.ResponseWriter
处理程序中的,这也是正确的,即使没有从处理程序中惊慌也被视为对请求的成功处理,并因此将HTTP 200状态发送回
您可以将http.Request
和http.ResponseWriter
值传递给其他函数和新的goroutine,但必须小心:如果要从多个goroutine中读取/修改这些值,则应使用显式同步(例如,锁,通道)。从多个goroutine发送回数据)。
请注意,看来,如果您的处理程序goroutine和新的goroutine都只读取/检查了http.Request
,则可能仍然有问题。是的,多个goroutine可以读取同一变量而无需同步(如果没有人修改它)。但是,调用的某些方法http.Request
也会修改http.Request
,并且如果没有同步,则无法保证其他goroutine从此更改中会看到什么。例如,Request.FormValue()
返回与给定键关联的表单值。但是,此方法调用,ParseMultiPartForm()
并且ParseForm()
在必要时会对其进行修改http.Request
(例如,它们设置Request.PostForm
和Request.Form
字段)。
所以,除非你同步够程,你不应该传递Request
和ResponseWriter
新够程,但是从需要采集数据Request
的处理够程,并通过只如struct
持有所需要的数据。
您的第二个示例:
foo := int64(0)
bar := func() {
// do slow things with foo
}
go bar()
很好
这是一个闭包,它引用的局部变量只要可以访问就可以保留。
请注意,您也可以将局部变量的值作为参数传递给匿名函数调用,如下所示:
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所做的更改是否需要对他人可见-
但这仍然需要同步,这将由通道解决方案取代)。
问题内容: 我对此有一些奇怪的问题。 我们正在使用Xvfb虚拟桌面管理器,并希望在继续之前确保其正在运行。使用纯外壳,我可以轻松地做到这一点: 这正是我所需要的,只有一行包含有关Xvfb proc的信息。接下来,我要将其合并到我的Java程序中并解析结果并存储正在运行的Xvfb进程的PID。所以我正在尝试: 奇怪的是,如果我使用“ ps -ef”,则在运行我的应用程序时,会得到大量的进程转储到控制
问题内容: 我有多个goroutine试图同时在同一频道上接收。似乎最后一个在通道上开始接收的goroutine获得了值。这是语言规范中的某个地方,还是未定义的行为? 输出: 操场上的例子 编辑: 我只是意识到它比我想的还要复杂。该消息在所有goroutine中传递。 输出: 操场上的例子 问题答案: 是的,它很复杂,但是有一些经验法则可以使事情变得简单得多。 宁愿使用 传递给go-routine
问题内容: 我有一些脚本应该已经停止运行,但是永远挂在身边。我是否可以通过某种方式以一种可读的方式弄清楚它们正在向STDOUT和STDERR写入什么内容? 例如,我尝试执行以下操作: 但这确实不起作用。无论如何,这是一个远射。 还有其他想法吗? 就其本身而言,它很冗长且难以理解。 注意:我 只 对它们的输出感兴趣,而对其他任何东西都不感兴趣。我有能力自己弄清其他事情;这个问题只集中在获得访问std
问题内容: 我想要一个小的“应用程序加载器”程序,该程序可以通过TCP从外部服务器接收其他二进制应用程序文件并运行它们。 我可以通过将传输的文件保存到硬盘上并使用system()调用来运行它来完成此操作。但是,我想知道是否有可能从内存中启动新应用程序而不接触硬盘驱动器。 加载新应用程序后,加载程序应用程序的状态无关紧要。我更喜欢使用C,但是也欢迎使用C ++解决方案。我还要坚持使用标准Linux
问题内容: 我的一项活动遇到了一个奇怪的问题。从拍照/录像回来时,我正在显示一个对话框,允许用户命名相机。用户按下“确定”后,我将使用所请求的文件名发送给主题,该主题将复制文件(并显示进度对话框)。 由于某种原因,即使我调用,总是在主线程上调用执行复制的函数。 更改呼叫以解决问题。我还是想知道为什么它不起作用… 问题答案: 并且是那里最混乱的运营商。前者确保订阅副作用在指定的调度程序(线程)上发生
问题内容: 假设我有一个小型数据库,其中包含三列:“ id1”,“ id2”和“ date”。我在字段“ id1”上建立数据库索引,因为它是一个经常选择的字段(许多选择查询都使用ex来运行:其中“ id1” = 125548)。 在某些特定的查询中,我需要根据未建立索引的表中的“日期”字段对用户的记录进行排序。我的好奇心是如果对日期进行排序操作(基本上是按订单执行的操作)字段将在整个数据库上运行,