我希望我的go常规工作者(ProcessToDo()
在下面的代码中)在关闭所有“排队”工作之前等待。
工作例程具有一个“待办事项”通道(已缓冲),通过该通道将工作发送给它。它有一个“完成”通道来告诉它开始关闭。该文档说,如果满足多个选择之一,则通道上的选择将选择一个“伪随机值”……这意味着在所有缓冲工作完成之前将触发关闭(返回)。
在下面的代码示例中,我希望所有20条消息都可以打印…
package main
import (
"time"
"fmt"
)
func ProcessToDo(done chan struct{}, todo chan string) {
for {
select {
case work, ok := <-todo:
if !ok {
fmt.Printf("Shutting down ProcessToDo - todo channel closed!\n")
return
}
fmt.Printf("todo: %q\n", work)
time.Sleep(100 * time.Millisecond)
case _, ok := <-done:
if ok {
fmt.Printf("Shutting down ProcessToDo - done message received!\n")
} else {
fmt.Printf("Shutting down ProcessToDo - done channel closed!\n")
}
close(todo)
return
}
}
}
func main() {
done := make(chan struct{})
todo := make(chan string, 100)
go ProcessToDo(done, todo)
for i := 0; i < 20; i++ {
todo <- fmt.Sprintf("Message %02d", i)
}
fmt.Println("*** all messages queued ***")
time.Sleep(1 * time.Second)
close(done)
time.Sleep(4 * time.Second)
}
done
您完全不需要使用通道,因为您可以通过关闭todo
通道本身来发出关闭信号。
并for range
在通道上使用,它将迭代直到通道关闭且其缓冲区为空。
您应该有一个done
通道,但只有这样,goroutine本身才能发出信号,表明它已完成工作,因此主goroutine可以继续或退出。
此变体与您的变体等效,简单得多,并且不需要time.Sleep()
调用来等待其他goroutine(反正太错误和不确定)。在GoPlayground上尝试一下:
func ProcessToDo(done chan struct{}, todo chan string) {
for work := range todo {
fmt.Printf("todo: %q\n", work)
time.Sleep(100 * time.Millisecond)
}
fmt.Printf("Shutting down ProcessToDo - todo channel closed!\n")
done <- struct{}{} // Signal that we processed all jobs
}
func main() {
done := make(chan struct{})
todo := make(chan string, 100)
go ProcessToDo(done, todo)
for i := 0; i < 20; i++ {
todo <- fmt.Sprintf("Message %02d", i)
}
fmt.Println("*** all messages queued ***")
close(todo)
<-done // Wait until the other goroutine finishes all jobs
}
还要注意,工作程序goroutine应该使用来表示信号已完成,defer
因此,如果主工作程序以某种意外的方式或发生紧急情况返回,则不会阻塞主工作程序。因此,它应该这样开始:
defer func() {
done <- struct{}{} // Signal that we processed all jobs
}()
您还可以sync.WaitGroup
用于将主goroutine同步到worker(以等待它)。实际上,如果您打算使用多个工作程序例程,那比从done
通道读取多个值更干净。同样,WaitGroup
由于它带有一个Done()
方法(这是一个函数调用),因此用来表示完成也更简单,因此您不需要匿名函数:
defer wg.Done()
有关完整的示例,请参见JimB的答案WaitGroup
。
使用forrange
信道同步,因此你不需要任何额外的代码,将同步访问:如果你想使用多工作够程也是地道的todo
通道或在收到该职位。并且,如果您关闭中的todo
频道main()
,则会正确地向所有工作html" target="_blank">程序发出信号。但是,当然,所有排队的作业将只被接收和处理一次。
现在,使用WaitGroup
用于使主goroutine等待工作程序使用的变体(JimB的答案):如果您希望有1个以上的工作程序goroutine,该怎么办?同时(最有可能并行)处理您的工作?
您需要在代码中添加/更改的唯一一件事是:真正启动多个代码:
for i := 0; i < 10; i++ {
wg.Add(1)
go ProcessToDo(todo)
}
现在,您无需更改任何其他内容,便有了一个正确的并发应用程序,该应用程序使用10个并发goroutine接收并处理您的作业。而且我们没有使用任何“丑陋的”time.Sleep()
(我们只使用了“丑陋的”,而只是模拟了缓慢的处理,而不是等待其他goroutine),并且您不需要任何额外的同步。
问题内容: 接下来的缓冲区在哪里…以及如何将其关闭? 我正在像这样的python程序中写出到stdout: 这里有一些缓冲: 我尝试了以下方法来摆脱可能的缓冲…但是没有运气: 如上使用-u标志和python调用 在每次sys.stdout.write()调用之后调用sys.stdout.flush()…所有这些都创建了一个带有python的缓冲流,等待一分钟左右以打印出前几行。 使用以下修改的命令
是否有一个工具或库可以将PROBUFF对象映射到POJO。我想让pojo实现我无法使用PROBUFF对象实现的其他接口。或者我必须手动执行此转换?
当我打开netrw并选择一个文件时,它会在一个新缓冲区中打开。这意味着如果我转到之前打开的缓冲区,我将返回netrw,而不是我之前编辑的文件。 我如何改变这种行为,这样我就可以在netrw的缓冲区中打开新文件,或者关闭我用来打开文件的缓冲区?
问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案会得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 7年前关闭。 我想知道的优点和缺点 Google协议缓冲区 JSON格式 XML格式 我想为两个应用程序实现一个通用框架,一个在Perl中,第二个在Java中。因此,希望创
我正在使用流协议编写服务器,所以我需要做一些事情,比如找到标题的结尾,复制它,然后在提升缓冲区中解析其他东西。当我发现使用字符串操作的最佳方法(在其中找到字符串,使用迭代器复制/删除等等)是std::字符串。但是我使用的是char数组缓冲区。所以我需要有两个缓冲区——char数组和std::字符串——每次我需要使用缓冲区进行操作时,我需要将char数组转换为std::字符串,完成我的工作,然后使用