使用通道的多个goroutine的同步

使用通道的多个goroutine的同步,go,concurrency,synchronization,channel,goroutine,Go,Concurrency,Synchronization,Channel,Goroutine,我需要使用单个任务队列和单个结果队列启动多个worker。每个工人应在不同的goroutine中启动。在退出程序之前,我需要等待所有工作人员完成并且任务队列为空。 我已经为goroutine同步准备了一个小例子。 其主要思想是我们统计队列中的任务,并等待所有工人完成工作。但当前的实现有时会失去价值。 为什么会发生这种情况以及如何解决这个问题? 示例代码: 导入( “fmt” “操作系统” “操作系统/信号” “strconv” ) const num_workers=5 类型workerChan

我需要使用单个任务队列和单个结果队列启动多个worker。每个工人应在不同的goroutine中启动。在退出程序之前,我需要等待所有工作人员完成并且任务队列为空。 我已经为goroutine同步准备了一个小例子。 其主要思想是我们统计队列中的任务,并等待所有工人完成工作。但当前的实现有时会失去价值。 为什么会发生这种情况以及如何解决这个问题? 示例代码:

导入(
“fmt”
“操作系统”
“操作系统/信号”
“strconv”
)
const num_workers=5
类型workerChannel chan uint64
//为任务设置通道
var工作通道
//为任务计数器创建通道
通道通道通道通道
//任务计数器
var tskCnt int64
//工人职能
func InitWorker(输入workerChannel,结果chan字符串,num int){
为了{
挑选{
case inp:=用于等待goroutines完成。关闭通道以退出通道上的循环读取

package main

import (
    "fmt"
    "sync"
)

type workerChannel chan uint64

const num_workers = 5

func main() {

    results := make(chan string)
    workCh := make(workerChannel)

    // Start workers
    var wg sync.WaitGroup
    wg.Add(num_workers)
    for i := 0; i < num_workers; i++ {
        go func(num int) {
            defer wg.Done()
            // Loop processing work until workCh is closed
            for w := range workCh {
                results <- fmt.Sprintf("worker %d, task %d", num, w)
            }

        }(i)
    }

    // Close result channel when workers are done
    go func() {
        wg.Wait()
        close(results)
    }()

    // Send work to be done
    go func() {
        for i := 0; i < 21; i++ {
            workCh <- uint64(i)
        }
        // Closing the channel causes workers to break out of loop
        close(workCh)
    }()

    // Process results. Loop exits when result channel is closed.
    for r := range results {
        fmt.Println(r)
    }
}
主程序包
进口(
“fmt”
“同步”
)
类型workerChannel chan uint64
const num_workers=5
func main(){
结果:=制造(成串)
工作通道:=制造(工作通道)
//开始工作
var wg sync.WaitGroup
工作组添加(工人数量)
对于i:=0;i
等待组版本

package main

import (
    "log"
    "sync"
)

func worker(in chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := range in {
        log.Println(i)
    }

}

func main() {
    in := make(chan int)
    lc := 25
    maxValue := 30
    wg := sync.WaitGroup{}
    wg.Add(lc)
    for i := 0; i < lc; i++ {
        go worker(in, &wg)
    }

    for c := 0; c <= maxValue; c++ {
        in <- c
    }
    close(in)
    wg.Wait()
}
主程序包
进口(
“日志”
“同步”
)
func worker(在chan int中,wg*sync.WaitGroup){
推迟工作组完成()
对于i:=中的范围{
log.Println(i)
}
}
func main(){
in:=制造(成交量)
立法会:25
最大值:=30
wg:=sync.WaitGroup{}
工作组增补(lc)
对于i:=0;i对于c:=0;c,在两个版本中,您都提供从工作进程内部关闭通道。我的情况不是这样。在我的情况下,队列将在运行时更新,我不知道数据的结尾在哪里。假设远程主机枚举文件并向队列提供文件名。工作进程正在根据文件名计算哈希(该过程耗时长达30秒)。我想启动一些worker和goroutine,它们将接收文件名并将它们放入队列。每个worker都比收集器慢得多。在文件结束时,将收到一个特殊命令,我们必须等待完成队列。1.我从main关闭通道,而不是从worker关闭通道。在创建它的同一个函数/对象。2.关闭通道仅在写入时关闭它,所有缓冲消息将继续处理。3.我不理解这种情况。它是HTTP服务器?从发布/子队列读取的守护进程?还是作业?它可以工作!但对于这种情况,任务将等待一个工作进程被释放。我想实现用于生成任务的goroutine能够将尽可能多的项目放入队列的情况下,因为我们有可用内存。所有这些项目都将与Worker一起逐个进行。是否可能?我前面介绍了其中一个用例。注释增加workCh通道的大小是否足够?如果不足够,则使用来实现没有大小限制。@CeriseLimón,如果使用缓冲通道会有区别吗?例如,
results:=make(chan string,num_workers)
我在这里修改了您的示例:,结果似乎是有序的,但我不明白为什么。@StevenFerrer由于实现的细节,结果是有序的。您的程序以其他顺序打印结果是有效的。@CeriseLimón,感谢您的快速响应。您是对的,我用代码尝试了它,结果是正确的不是有序的。我希望有一种方法可以真正让结果有序。类似于队列,但仍然保持作业的异步处理。
package main

import (
    "log"
    "os"
)

func worker(in chan int, end chan struct{}) {
    defer func() { end <- struct{}{} }()
    for i := range in {
        log.Println(i)
    }

}

func main() {
    in := make(chan int)
    lc := 25
    maxValue := 30
    end := make(chan struct{})
    var fin int
    go func() {
        for {
            <-end
            fin++
            log.Println(`fin`, fin)
            if fin == lc {
                break
            }
        }
        close(end)
        os.Exit(0)
    }()
    for i := 0; i < lc; i++ {
        go worker(in, end)
    }

    for c := 0; c <= maxValue; c++ {
        in <- c
    }
    close(in)
    <-make(chan struct{})
}