传递任何值到取消通道会导致程序挂起。

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

Passing any value over cancel channel causes program to hang

问题

我正在尝试使用工作协程来检查到一定距离的直径,在一次只处理一个瓦片时效果很好,但是当处理多个瓦片时,速度会显著下降。我猜想这是因为即使不再需要,很多协程仍在运行。我添加了一个失败通道来告诉所有正在运行的协程关闭,但这样做会导致应用程序挂起。实际上,即使我不消耗通道的值,将任何值传递给通道也会导致应用程序挂起。

下面是使用通道的例程:

caught := 0
loop:
	for angle := float64(0); angle < 360; angle++ {
		select {
		case <-failChannel:
			break loop
		default:
			log.Print(angle)
		}

	}
	channelOut <- []int{radius, caught}

这是使用通道的循环:

for {
	select {
	case circle := <-channelOut:
		if circle[1] == 0 {
			radiusMap[circle[0]] = 0
			if _, radius := testLine(radiusMap); radius <= circle[0] {
				failChannel <- 0
			}
		} else {
			radiusMap[circle[0]] = 1
		}
			
	default:    
	}
}

这个循环将整数传递给failChannel。我使用整数通道是因为我想看看较小的半径是否失败,如果失败则停止。目前我只是将其设置为任意整数进行测试。

有人知道为什么会出现挂起的情况吗?对我来说这似乎没有道理。

英文:

I am trying to use worker goroutines to check diameters out to a certain distance, it works great when I do one tile at a time, but when I do a bunch, there is a massive slow down. I figure this is because a lot of goroutines are still running even though they are no longer needed. I added a fail channel to tell all running goroutines to close up shop, but doing this causes the app to hang. Actually, passing any value to the channel causes the app to hang, even if I don't consume it.

 caught := 0
loop:
	for angle := float64(0); angle &lt; 360; angle++ {
		select {
		case &lt;-failChannel:
			break loop
		default:
         log.Print(angle)
		}

	}
	channelOut &lt;- []int{radius, caught}

is the routine that uses the channel

for {
		select {
		case circle := &lt;-channelOut:
			if circle[1] == 0 {
				radiusMap[circle[0]] = 0
				if _, radius := testLine(radiusMap); radius &lt;= circle[0] {
					failChannel &lt;- 0
 	

				}
			} else {
				radiusMap[circle[0]] = 1

			}
			
		default:    
		}
	}

Is the loop that will pass the int to the failChannel. I am doing an int channel because I want to see if a lower radius failed, and if so stop. I made it just any int right now as a test.

Does anyone have any clue why this would be hanging? It doesn't seem to make sense to me.

答案1

得分: 2

你可以关闭一个通道来表示完成:

failed := make(chan struct{})
select {
case <-failed:
}

在另一个 goroutine 中:

close(failed)

这将导致 failed case 发生。这适用于任意数量的 goroutine 监听 failed。但要小心,只能执行一次关闭操作,因为关闭一个已经关闭的通道会引发 panic。你可以使用以下模式:

// Stopper 通过在调用 Stop 时关闭 C 来表示完成
type Stopper struct {
	C    chan struct{}
	once sync.Once
}

// NewStopper 创建一个新的 Stopper
func NewStopper() *Stopper {
	return &Stopper{
		C: make(chan struct{}),
	}
}

// Stop 关闭 C。可以安全地多次调用
func (s *Stopper) Stop() {
	s.once.Do(func() {
		close(s.C)
	})
}
英文:

You can close a channel to signal completion:

failed := make(chan struct{})
select {
case &lt;-failed:
}

In another goroutine:

close(failed)

Will cause the failed case to happen. This will work with any number of goroutines listening on failed. Be careful to only do this once though, because closing an already close channel will panic. You could use this pattern:

// A Stopper signals completion over C by closing it when Stop is called
type Stopper struct {
	C    chan struct{}
	once sync.Once
}

// NewStopper creates a new Stopper
func NewStopper() *Stopper {
	return &amp;Stopper{
		C: make(chan struct{}),
	}
}

// Stop closes C. It is safe to call multiple times
func (s *Stopper) Stop() {
	s.once.Do(func() {
		close(s.C)
	})
}

huangapple
  • 本文由 发表于 2016年4月11日 21:34:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/36550292.html
匿名

发表评论

匿名网友

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

确定