Go -永远停止循环

vkc1a9a2  于 2023-08-01  发布在  Go
关注(0)|答案(3)|浏览(93)

我有一个异步进程,它应该永远持续下去,看起来像这样:

func asyncForeverTask() {
  for {
    anyTask()
  }
}

func main() {
  go asyncForeverTask()

  server.run(8080)
}

字符串
我希望能够在某个请求到达服务器时停止此for循环。
我知道我需要使用context.WithCancel(),但我不知道如何集成它才能工作。我知道以下语法:

for {
  select {
  case <-ctx.Done:
    return
  case <-otherCh:
    // do smh.
  }
}


但是asyncForeverTask不受来自任何其他Ch的信号的影响,而是永远运行。我是一个noobie去,并会感谢任何类型的帮助。

tp5buhyn

tp5buhyn1#

你可以用一个频道来做:

var stopAsync = make(chan struct{})

func asyncForeverTask() {
  for {
    select {
      case <-stopAsync:
         return
      default:
    }
    anyTask()
  }
}

字符串
要取消,只需关闭通道。你必须确保通道只关闭一次,否则你会恐慌。
您也可以使用上下文来执行此操作:

func main() {
   ctx,cancel:=context.WithCancel(context.Background())
   go asyncForeverTask(ctx)
   ...
}

func asyncForeverTask(ctx context.Context) {
  for {
    select {
      case <-ctx.Done():
         return
      default:
    }
    anyTask()
  }
}


或者:

func asyncForeverTask(ctx context.Context) {
  for {
    if ctx.Err()!=nil {
       return
    }
    anyTask()
  }


要停止,请调用返回的cancel函数:

...
cancel()


如果还需要停止anyTask,则必须经常检查通道闭包或上下文闭包,并从任务返回。

3z6pesqy

3z6pesqy2#

通道和上下文可以工作,并且可以很方便。但他们不是你唯一的选择。对于这样的东西,简单的atomic.Bool可能更简单。类似于:

package main

import (
    "fmt"
    "sync/atomic"
    "time"
)

func asyncForeverTask(stop *atomic.Bool) {
    for {
        if stop.Load() {
            return
        }
        fmt.Println("I'm still running")
        time.Sleep(1 * time.Second)
    }
}

func main() {
    var stop atomic.Bool
    go asyncForeverTask(&stop)
    time.Sleep(10 * time.Second)
    stop.Store(true)
}

字符串

44u64gxh

44u64gxh3#

信不信由你,但这个简单的关闭方法也有效:

package main

import (
    "fmt"
    "time"
)

var done bool = false

func asyncForeverTask() {
    for {
        if done {
            return
        }
        fmt.Println("I'm still running")
        time.Sleep(1 * time.Second)
    }
}

func main() {
    go asyncForeverTask()
    time.Sleep(10 * time.Second)
    done = true
}

字符串
是的,我知道全局变量是邪恶的。只是为了记录。

相关问题