GoLang,将资源放回通道会导致我的程序挂起。

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

GoLang, put resource back to channel hang my program

问题

这段代码中的问题可能是由于通道的阻塞导致的hang。在这段代码中,当ret为真时,会执行mr.registerChannel <- worker_str这一行代码,将worker_str放回registerChannel通道中。但是,如果没有其他goroutine从registerChannel中接收数据,那么这个操作将会导致阻塞,从而导致hang。

为了解决这个问题,你可以考虑使用带有缓冲区的通道,或者在接收数据之前使用非阻塞的方式发送数据。如果你使用带有缓冲区的通道,可以在初始化registerChannel时指定缓冲区的大小,例如registerChannel := make(chan string, bufferSize)。这样,即使没有其他goroutine从通道中接收数据,发送操作也不会阻塞,直到缓冲区被填满。

另外,你还可以使用select语句来实现非阻塞的发送操作。你可以将发送操作放在一个select语句中,并使用default分支来处理通道已满的情况。例如:

select {
case mr.registerChannel <- worker_str:
    // 发送成功
default:
    // 通道已满,执行其他操作
}

通过这样的方式,即使通道已满,发送操作也不会阻塞,而是会执行default分支中的代码。

希望这些解释对你有帮助!如果还有其他问题,请随时提问。

英文:
  for i := 0; i &lt; mr.nMap; i++ {
    DPrintf(&quot;worker number is %d\n&quot;, mr.workerNumber)

    worker_str = &lt;- mr.registerChannel

    DPrintf(&quot;Worker_str is %s \n&quot;,worker_str)

    args := &amp;DoJobArgs{mr.file,&quot;Map&quot;,i,mr.nReduce}
    var reply DoJobReply
    var ret bool
    ret = call(worker_str, &quot;Worker.DoJob&quot;, args, &amp;reply)
    if ret  {
    	fmt.Println(&quot;wk worker done.\n&quot;)
      fmt.Println(worker_str)
      mr.registerChannel &lt;- worker_str   // &lt;=======stuck here
    } else
    {
      fmt.Println(&quot;wk worker fail.\n&quot;)
    }

    DPrintf(&quot;map finished.&quot;)

  }

btw, mr is instance of this:

type MapReduce struct {
	nMap            int    // Number of Map jobs
	nReduce         int    // Number of Reduce jobs
	file            string // Name of input file
	MasterAddress   string
	registerChannel chan string
	DoneChannel     chan bool
	alive           bool
	l               net.Listener
	stats           *list.List

	// Map of registered workers that you need to keep up to date
	Workers map[string]*WorkerInfo

	// add any additional state here
	workerNumber    int
}

My code hang when I do this &quot;mr.registerChannel &lt;- worker_str &quot;

I really don't understand why.
worker_str is available, and I want to put this resource back after using this worker. Put it back to channel, let next job use available workers.

Why it hang?
thanks

答案1

得分: 6

在Go语言中,如果通道没有缓冲区,它们可以用于同步。在这里,负责消费mr.registerChannel的进程试图向其写入数据。当你从非缓冲通道读取或写入数据时,你会等待直到另一端有进程进行读取或写入。

因此,当这个代码块试图向通道写入数据时,它会阻塞等待其他进程读取它所写入的数据。由于这个代码块还负责读取数据,它将永远等待自己,导致死锁。你需要重新设计代码,将字符串传递给其他进程进行读取,或者使用带缓冲区的通道,并且不期望在读取行worker_str = <- mr.registerChannel上发生阻塞。这将需要重写为for/select或其他形式的代码。

英文:

In go, channels can be used for synchronization if they are not buffered. Here, the process that is responsible for consuming the mr.registerChannel is trying to write to it. When you read from, or write to and unbuffered channel, you will wait until there is another process on the other end to write to, or read from the channel, respectively.

So, when this block attempts to write to the channel, it blocks waiting for someone to read what it wrote. Since this block is also responsible for reading, it will wait forever for itself in a deadlock. You need to either redesign this so that you hand the string back off to something else to read, or you need to use a buffered channel and don't expect to trap on the read line worker_str = &lt;- mr.registerChannel. That would have to be re-written as a for/select or something.

huangapple
  • 本文由 发表于 2014年5月22日 10:40:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/23796961.html
匿名

发表评论

匿名网友

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

确定