select块如何等待ctx.Done()?

问题描述 投票:0回答:2

在下面的代码中:

    ctx, cancel := context.WithTimeout(req.Context(), 5000*time.Second)

    // Wait for the response or timeout
    select {
    case <-ctx.Done():
        log.Println("timeout, cancel work...")

        // Cancel the request and wait for it to complete
        // this will shutdown the go-routine immediately
        tr.CancelRequest(req)
        log.Println(<-ch)

    case err := <-ch:
        // do something
    }

select同时等待两个接收操作。

一个接收操作(<-ch)是块操作

在执行select块期间,是否在ctx.Done()块中多次调用select以验证ctx.Done()是否返回通道?直到<-ch被阻止...

go channel
2个回答
0
投票

Spec: Select statements:

对于语句中的所有情况,接收操作的通道操作数以及send语句的通道和右侧表达式仅被精确评估一次,按源顺序输入“ select”语句。

select仅调用一次ctx.Done()。它返回一个通道,并监视是否可以继续从该通道接收操作。

如果5000*time.Second超时到期,或者取消了父上下文(req.Context())(例如超时或调用了其cancel()函数),则将关闭ctx.Done()返回的通道,因此可以继续接收(不再是障碍)。 Spec: Receive operator:

closed通道上的接收操作总是可以立即进行,在接收到任何先前发送的值后会产生元素类型的zero value


0
投票

通常,当您使用阻塞通道和超时功能时,可以将其置于for-select循环中。

ctx, cancel := context.WithTimeout(req.Context(), 5000*time.Second)

    // Wait for the response or timeout
   for {
    select {
    case <-ctx.Done():
        log.Println("timeout, cancel work...")

        // Cancel the request and wait for it to complete
        // this will shutdown the go-routine immediately
        tr.CancelRequest(req)
        log.Println(<-ch)
        break
    case err := <-ch:
        // do something
        break
    }
   }

在这种情况下,<-ch不再阻塞,并且选择多次调用ctx.Done()。如果不使用for循环,则ctx.Done()仅被调用一次(如@icza所指出的)

© www.soinside.com 2019 - 2024. All rights reserved.