当前位置: 首页 > 面试题库 >

在这种情况下,Go HTTP处理程序goroutine是否应立即退出?

养翔
2023-03-14
问题内容

我有一个这样的Go HTTP处理程序:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    if cn, ok := w.(http.CloseNotifier); ok {
        go func(done <-chan struct{}, closed <-chan bool) {
            select {
            case <-done:
            case <-closed:
                fmt.Println("client cancelled....................!!!!!!!!!")
                cancel()
            }
        }(ctx.Done(), cn.CloseNotify())
    }

    time.Sleep(5 * time.Second)

    fmt.Println("I am still running...........")

    fmt.Fprint(w, "cancellation testing......")
})

该API正常工作,然后使用curl在请求完成之前我故意用终止curl命令Control-C,在服务器端我确实看到了client cancelled....................!!!!!!!!!get注销,但过一会儿I am still running...........get退出后,我还以为这个goroutine将立即终止!

那么,这是理想的行为,还是我做错了什么?

如果可以预料,由于任何goroutine将完成其工作,那么提前取消的意义何在?

如果我做错了什么,请帮我指出正确的方法。


问题答案:

您创建了一个contex.Context可以取消的,您可以在客户端关闭连接时取消它,但是您不会检查上下文,并且如果取消它,处理程序也不会做任何不同的事情。上下文仅
携带 超时和取消信号,它不具有杀死/终止goroutines的能力或意图。goroutine本身必须监视此类取消信号并对其采取行动。

因此,您看到的是代码的预期输出。

您想要监视的是上下文,如果上下文被取消,则从处理程序中“立即”返回。

当然,如果您正在“睡觉”,则无法同时监视上下文。因此,请改用time.After(),如本例所示:

mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    if cn, ok := w.(http.CloseNotifier); ok {
        go func(done <-chan struct{}, closed <-chan bool) {
            select {
            case <-done:
            case <-closed:
                fmt.Println("client cancelled....................!!!!!!!!!")
                cancel()
            }
        }(ctx.Done(), cn.CloseNotify())
    }

    select {
    case <-time.After(5 * time.Second):
        fmt.Println("5 seconds elapsed, client didn't close")
    case <-ctx.Done():
        fmt.Println("Context closed, client closed connection?")
        return
    }

    fmt.Fprint(w, "cancellation testing......")
})


 类似资料:
  • 你好,我正在学习OOP,通过编写一个虚拟的库管理项目在Java。 在serachBook()中,如果在ArrayList中找到book,则返回book对象,如果未找到,则抛出自定义异常BookNotFound。 问题1:它应该只返回null并在调用代码时检查返回值是否为null,还是抛出自定义异常BookNotFound。 目前我认为BookNotFinder是合适的,并且目前正在这样做。然而,我

  • 我用干净的架构在android项目上工作。 我有以下课程: 使用public dispose()方法从onNext实现中释放序列。 但我还是不明白使用它的好处。是否用于在销毁视图时从observable取消订阅,以便从转到并关闭发射器上的订阅?

  • 问题内容: 想象这样的情况: 现在,我从理论上担心,在哪里克隆状态(中的第四条语句),可能会发生我没有获得该状态的最新版本的情况- 由于先前调用的某些调用正在等待中,这是否是正确的假设? 现在,我的问题是,如果我以以下方式(基本上与回调参数一起使用)重写上述代码,它会更安全吗?(就不处于不同步状态而言)。 我是否还需要在内部采取一些其他措施(第二个重写版本)? ps。只是更改状态的函数-假设当用户

  • 问题内容: 该代码应获取或创建一个对象,并在必要时对其进行更新。该代码已在网站上投入生产。 在某些情况下-当数据库繁忙时-它会引发异常“ DoesNotExist:MyObj匹配查询不存在”。 我在ubuntu上使用了一个innodb mysql数据库。 我如何安全地处理此问题? 问题答案: 基本上get_or_create 可能会失败 -如果你查看其来源,就会发现它是:get,if-proble

  • 问题内容: 因为调用flush()获取每个实体都从内存持久到数据库。因此,如果我使用过多的不必要的flush()调用,可能会花费很多时间,因此对于性能而言不是一个好的选择。这是一种我不知道何时调用flush()的情况? 我的问题是:是否可以避免调用No.1同花顺? 我担心的事情是:为了执行 item.setOrder(ord) ,我们需要ord的数据库ID。而且仅调用 em.persist(ord

  • 我有一个粒子模拟项目,我已经工作了很多个小时,我将发布两个类。一个是粒子类,一个是main和Canvas类。我创建一个画布,然后得到它的BufferStrategy和一个Graphics在上面绘制。我使用更新循环来更新每一帧的粒子,并使用渲染循环来渲染每一帧的粒子。更新和渲染都是通过调用粒子数组列表中每个粒子的自渲染和自更新方法来完成的。现在这是我的问题。我有一个MouseListener,它在中