简体   繁体   English

golang从同一个频道读写

[英]golang read and write from same channel

The problem code is:问题代码是:

go func() {
    defer wg.Done()
    for {
        task := <-tasks

        if task.Attemts >= .5 {
            tasks <- task # <- error
        }

        Println(task)
    }
}()

Tasks filling with tasks <- Task{"1", rand.Float64()} in another loop.在另一个循环中填充tasks <- Task{"1", rand.Float64()}

And now we've got deadlock...现在我们陷入了僵局……

Full example: https://play.golang.org/p/s1pnb1Mu_Y完整示例: https : //play.golang.org/p/s1pnb1Mu_Y

The point of my code is - create web scraper , which one will try to parse urls after fails.我的代码的重点是 - 创建 web scraper ,它会在失败后尝试解析 url。 Take some attempts and then drop url.进行一些尝试,然后删除 url。

Might be in golang we have some more ideomatic way to solve this problem, cuz i don't know.可能在 golang 中,我们有一些更理想化的方法来解决这个问题,因为我不知道。

You are using a nonbuffered channel so when you try to send with tasks <- task execution in that goroutine sits there waiting for something else to read on the channel.您使用的是非缓冲通道,因此当您尝试使用tasks <- task发送tasks <- task该 goroutine 中的tasks <- task执行坐在那里等待其他内容在通道上读取。 Since nothing else is reading on the channel you get a deadlock.由于频道上没有其他内容正在阅读,因此您会陷入僵局。

The only way to make this specific code work is to have a fully dedicated consumer or use a buffered channel.使此特定代码工作的唯一方法是拥有一个完全专用的使用者或使用缓冲通道。 Even with a buffered channel here you could get a deadlock if the buffer fills up at the point your single consumer tries to send on it.即使这里有一个缓冲通道,如果缓冲区在您的单个消费者尝试发送时填满,您也可能会陷入死锁。

If you really need to send from that same goroutine you're going to have to spawn a new goroutine just to send it.如果你真的需要从同一个 goroutine 发送,你将不得不生成一个新的 goroutine 来发送它。 Something along the lines of类似的东西

go func() {
    tasks <- task
}()

Or you could have something like this:或者你可以有这样的事情:

requeue = make(chan Task) // could buffer if you want
go func() {
    for {
        tasks <- requeue
    }
}()
for {
    task := <-tasks

    if task.Attemts >= .5 {
        requeue <- task
    }

    Println(task)
}

Handling the closing of that channel and the like of course.当然,处理该通道的关闭等。

If this is the only goroutine reading from the channel, it cannot also write to it.如果这是从通道读取的唯一 goroutine,则它也不能写入。

It is possible if you used a buffered channel, it would sort of work for a little bit, but that would only push your problem back.如果您使用缓冲通道,它可能会有点工作,但这只会将您的问题推回去。 What you really want to do is likely use你真正想做的可能是使用

go func(){
   tasks <- task
}()

instead of the simple tasks <- task .而不是简单的tasks <- task That will offload the writing to another goroutine, so this one can go right back to reading.这会将写入卸载到另一个 goroutine,因此这个 goroutine 可以直接返回读取。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM