如何在for循环中使选择语句(select case)非阻塞且没有默认情况。

huangapple go评论71阅读模式
英文:

How to make a select case non-blocking in for loop without default

问题

我有这段代码。

func Start() bool {
    for {
        if checkSomthingIsTrue() {
            if err := doSomthing(); err != nil {
                continue
            }
        }
        select {
        case <-ctx.Done():
            return true
        }
    }
}

如何使上述函数非阻塞,而不使用default: case。
不使用default case的原因是它会一直占用100%的CPU。

答案:
我使用了time.Ticker来进行节流。
谢谢。

英文:

I have this piece of code.

func Start() bool {
	for {
		if checkSomthingIsTrue() {
			if err := doSomthing(); err != nil {
				continue
			}
		}
		select {
		case &lt;-ctx.Done():
			return true
		}
	}
}

How to make the above function non blocking without using default: case.
reason to not use default case is because its eating up 100% CPU always.

Answer:
I have used time.Ticker to throttle
Thanks

答案1

得分: 6

这里存在一个基本误解。一个线程只能做两件事情:

  • 一个线程可以阻塞,等待某些事情发生。

  • 一个线程可以运行,使用 CPU。

如果一个线程从不阻塞,那么它将使用 100% 的可用 CPU。你无法使非阻塞代码使用少于 100% 的可用 CPU。

你有三个选项:

  1. 使用非阻塞代码,并接受 100% 的 CPU 使用率。

  2. 重新设计 checkSomthingIsTrue(),使其使用通道,并可以放在 select 块中。

    for {
        select {
        case <-ctx.Done():
            return true
        case <-whenSomethingIsTrue():
            if err := doSomthing(); err != nil {
                continue
            }
        }
    }
    
  3. 使用超时来限制循环,例如:

    // 每 100ms 进行一次轮询。
    const pollInterval = 100 * time.Millisecond
    for {
        select {
        case <-ctx.Done():
            return true
        case <-time.After(pollInterval):
            if checkSomthingIsTrue() {
                if err := doSomthing(); err != nil {
                    continue
                }
            }
        }
    }
    

还要注意,continue 没有意义,但这是另一个问题。

英文:

There is a fundamental misunderstanding here. A thread can do only two things:

  • A thread can block, waiting for something.

  • A thread can run, using CPU.

If a thread never blocks, then it uses 100% of the available CPU. You cannot make non-blocking code use less than 100% of the available CPU.

You have three options:

  1. Use non-blocking code, and accept the 100% CPU usage.

  2. Redesign checkSomthingIsTrue() so it uses a channel, and can be put inside the select block.

    for {
        select {
        case &lt;-ctx.Done():
            return true
        case &lt;-whenSomethingIsTrue():
            if err := doSomthing(); err != nil {
                continue
            }
        }
    }
    
  3. Use a timeout to throttle the loop, for example:

    // Poll every 100ms.
    const pollInterval = 100 * time.Millisecond
    for {
        select {
        case &lt;-ctx.Done():
            return true
        case &lt;-time.After(pollInterval):
            if checkSomthingIsTrue() {
                if err := doSomthing(); err != nil {
                    continue
                }
            }
        }
    }
    

Also note that continue makes no sense, but that is a different issue.

huangapple
  • 本文由 发表于 2021年6月17日 22:56:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/68021797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定