最近有小伙伴碰到了问了下面的问题。
handler拿到一个请求,然后把请求放到一个channel里面,一个gorutine一直在从这个channel取值做处理。如果我想在handler里面返回处理结果,是不是现在的流程无法实现呢?
他这样问我,因为自己是菜鸡无法回答,我打算自己尝试一下
首先搭了一些个简单的http服务器
func main(){
http.HandleFunc("/", handler)
http.ListenAndServe("localhost:8082", nil)
}
然后将goroutine和channel跑起来
func Test (){
ch := make(chan int, 1)
sign := make(chan byte, 2)
go func() {
for i := 0; i < 5; i++ {
ch <- i
time.Sleep(1 * time.Second)
}
close(ch)
fmt.Println("The channel is closed.")
sign <- 0
}()
go func() {
//这个循环会一直尝试从ch中读取信息出来 即使ch已经被发送端关闭
//但还是可以读信息出来 最后当ok 为false的时候 说明已经没有数据从ch中读出
//跳出循环 注意这种判断方式
for {
fmt.Printf("before extract channel len: %v ,", len(ch))
e, ok := <-ch
fmt.Printf("channel value: %d if extract ok :(%v) after extraction channel len : %v channel cap : %v \n", e, ok, len(ch), cap(ch))
if !ok {
break
}
time.Sleep(2 * time.Second)
}
fmt.Println("Done.")
sign <- 1
}()
//要是不添加两次取值的操作的话 主进程就会马上结束 这里相当于是实现了一个
//同步的操作 等待两个go func都结束之后 再结束主进程 注意这种技巧
<-sign
<-sign
}
基本无问题,然后对这个代码进行了改造,然后得到了如下的代码
结构体
type HandlerDemo struct {
writer http.ResponseWriter
request *http.Request
}
具体实现代码
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Println("start...")
//test response
/*w.WriteHeader(http.StatusOK) // 200
fmt.Fprintf(w, "this msg: %v\n", 123)
return*/
info:=HandlerDemo{}
info.writer=w
info.request=r
result:=HandlerDemo{}
ch := make(chan HandlerDemo, 1)
ch <- info
close(ch)
fmt.Println("ch is have data..")
go func() {
fmt.Println("start run goroutine..")
fmt.Println("try get ch val..")
e, ok := <-ch
fmt.Printf("channel value: %d if extract ok :(%v) after extraction channel len : %v channel cap : %v \n", e, ok, len(ch), cap(ch))
if ok{
result.writer=e.writer
result.request=e.request
fmt.Printf("result value: %d \n", result)
}
}()
time.Sleep(3 * time.Second)
fmt.Println("over...")
fmt.Println("this val is get and try response..")
result.writer.WriteHeader(http.StatusOK)
fmt.Fprintf(result.writer,"this response msg: %v\n", "hello")
return
}
可以看到,我卡了很久在这使用了Sleep才成功将信息返回。http输入必然输出,开启goroutine时相当于异步,通信还是会继续下去直到结束,它会先返回空值,在goroutine里返回会报错多次返回,于是我采用极端的方法做到了返回,拿到了久违的hello。但是这种方法显然不适合应用,改进方法将睡眠时间改为判断goroutine结束,这样就更加合理一些!!哈哈哈
有疑问加站长微信联系(非本文作者)