package main
import (
"context"
"fmt"
)
func gen(ctx context.Context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.Done():
fmt.Println("done")
default:
n += 1
ch <- n
}
}
}()
return ch
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
break
}
}
defer cancel()
}
期望 能打印出 "done"
应该是阻塞在 ch<-n 了。
cancel() 如果执行的比较晚,在 cancel 之前第六个 ch<-n 就已经执行了的话,就阻塞了。(main 逻辑相对比较长,比如还有一个 Println ,所以大概率 cancel 会比较晚。
可以试试这个:
package main
import (
"context"
"fmt"
)
func gen(ctx context.Context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.Done():
fmt.Println("done")
close(ch) // 关闭 channel ,range 结束
return
default:
n += 1
ch <- n
}
}
}()
return ch
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
cancel()
// break 不能 break,否则没有从 ch 中的读取,就会一直阻塞在 ch <- n
}
}
}
这个依然会打印 6 个,因为 cancel 的时候第六个 ch<-n 已经执行了。
在你的代码中,<-ctx.Done()
没有执行并打印 "done" 的原因是 cancel()
函数调用发生在 for n := range gen(ctx)
循环结束后,而循环结束的条件是 n == 5
。由于 cancel()
是在循环结束后被调用,此时 gen
函数中的 goroutine 已经因为 main
函数中的循环结束而不再从 ch
发送数据,因此 select
语句中的 case <-ctx.Done():
分支没有机会被执行。
为了解决这个问题,你需要确保在 main
函数中,在循环结束之前调用 cancel()
函数,并且让 gen
函数中的 goroutine 有机会响应 ctx.Done()
信号。你可以通过修改 main
函数来实现这一点,如下所示:
package main
import (
"context"
"fmt"
"time"
)
func gen(ctx context.Context) <-chan interface{} {
ch := make(chan interface{})
go func() {
n := 0
for {
select {
case <-ctx.Done():
fmt.Println("done")
return // 确保goroutine在接收到取消信号后退出
default:
n += 1
ch <- n
// 为了避免goroutine过快地发送数据,可以添加一点延迟
time.Sleep(100 * time.Millisecond)
}
}
}()
return ch
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
done := make(chan bool)
go func() {
for n := range gen(ctx) {
fmt.Println(n)
if n == 5 {
cancel() // 在n==5时取消context
done <- true
break
}
}
}()
<-done // 等待goroutine完成
}
在这个修改后的版本中,我添加了一个 done
通道来确保 main
函数等待 gen
函数中的 goroutine 完成其工作。当 n
等于 5 时,cancel()
被调用,并且 done
通道被发送一个值以通知 main
函数可以安全地继续执行。同时,我在 gen
函数的 goroutine 中添加了一个 return
语句,以确保在接收到取消信号后 goroutine 能够退出。此外,我还添加了一个小的延迟来模拟数据生成的过程,以避免在测试时过快地达到 n == 5
的条件。
最近,我使用了ThreadPoolExecutor和priorityqueue,并在将来遇到了这两种方法。对未来任务执行cancel()。和任务。remove(),将其从队列中移除。 更好的选择是什么?有什么区别吗?我可以保存两者的列表(从submit()接收的未来对象或任务本身),不确定要使用什么。。。 移除: 取消: 我使用了以下方法:http://docs.oracle.com/javase
问题内容: 我有一个包含单元测试的Go文件,其中一些使用了公共变量。我正在测试的代码中使用了另一个全局变量。所有这些都可能导致问题。 在Go中,当我们执行位于同一文件中的测试时,它们如何运行?并行还是下一个不会在前一个完成之前开始? 问题答案: 测试起来真的很容易: 使用运行它,输出显示它是顺序的: 因此,正常的测试是依次执行的,但是请不要忘记未定义顺序:如何依次运行golang测试? 还要注意,
问题内容: 我已经尝试了这两个代码,但是却没有执行,有人可以告诉我为什么吗? 提前致谢 问题答案: 试试这个代码: 它会在源元素的位置单击并按住,移至目标元素的位置,然后释放鼠标。 要么 它将单击并按住源元素的位置,移动给定的偏移量,然后释放鼠标。 要么 它将执行以上两个代码的操作。 我在Java上编写此代码。您可以转换为指定的语言。 从动作引用。
在上面的例子中,我们演示了一下如何去触发执行一个外部的进程。我们这样做的原因是我们希望从Go进程里面可以访问外部进程的信息。但有的时候,我们仅仅希望执行一个外部进程来替代当前的Go进程。这个时候,我们需要使用Go提供的exec函数。 package main import "syscall" import "os" import "os/exec" func main() { // 本例中
嘿,我在POM中做了这个配置。xml文件并行运行测试。但当我使用cmd进行“mvn验证”时,只有一个浏览器正在运行一个功能,而在完成一个功能文件的执行后,另一个功能正在运行。这是我的代码和pom。xml请建议我怎么做? 我正在使用cucumber 这是我的pom.xml代码: 提前感谢。
我制作了以下cronjob sh文件: 手动运行此文件时,作业将正确运行。