当前位置: 首页 > 面试题库 >

去例行程序不收集通道中的所有对象

笪涛
2023-03-14
问题内容

我有一个go-routine将对象添加到通道中,然后我有四个go- routines要处理通道的对象。处理不过是将对象添加到数组而已。但是有时,最终数组中缺少对象。因此,我假设某个时候通道停止收集对象。我有以下代码

package main

import (
    "log"
    "sync"
)

func main() {
    j := 0
    for {
        if j == 10 {
            break
        }
        wg := sync.WaitGroup{}
        months := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"}
        hits := make(chan string)
        i := 0
        wg.Add(1)
        go func() {
            defer close(hits)
            for {
                if i == 25 {
                    wg.Done()
                    return
                }
                for _, month := range months {
                    hits <- month
                }
                i++
            }
        }()

        temp := []string{}
        for updateWorker := 1; updateWorker <= 4; updateWorker++ {
            wg.Add(1)
            go func() {
                for hit := range hits {
                    temp = append(temp, hit)
                }
                wg.Done()
                return
            }()
        }

        wg.Wait()

        log.Printf("length of temp %+v\n", len(temp))
        j++
    }
}

我正在使用sync库来同步例程。我将同一进程循环10次以测试输出是否一致。我期望这样的输出:

length of temp 175

是175,因为我发送了7个月的字符串25次。但是有时输出少于175,我不知道为什么。我对围棋例程有点初学者。那么有人可以在这里帮助我找到原因吗?谢谢。


问题答案:

问题在于,updateWorkergoroutine都从hits通道收集了结果(到目前为止很好),并且它们都将结果存储在未 同步*
temp本地变量中。这不行。
*

必须同步访问多个goroutine中的所有变量(其中至少有一个是写操作)。

如果在启用了竞争检测器的情况下运行它,它会发出有关数据竞争的尖叫(go run -race app.go)。

如果将updateWorkergoroutine 的数量减少到1,它将立即产生有效的结果,因为这样我们就消除了应用程序的单个数据争用源:

for updateWorker := 1; updateWorker <= 1; updateWorker++ {
    // ...
}

如果要保留多个updateWorkergoroutine,则temp必须同步它们对共享变量的访问。

带有sync.Mutex

var (
    mu   sync.Mutex
    temp []string
)
for updateWorker := 1; updateWorker <= 4; updateWorker++ {
    wg.Add(1)
    go func() {
        for hit := range hits {
            mu.Lock()
            temp = append(temp, hit)
            mu.Unlock()
        }
        wg.Done()
        return
    }()
}

还要注意,在这个简单的示例中,通过使用多个updateWorkergoroutine并不会获得任何好处,与仅使用其中的一个相比,添加上述同步(锁定)甚至会使性能降低。



 类似资料:
  • 我的Eclipse中有一个运行在Windows 10上的MavenJava项目。该项目构建良好,并在目标文件夹中生成m-m.jar文件。 如何要求Maven收集所有需要运行这个项目的jar? 波姆。xml内容:

  • 我正在尝试使用 Jolt 转换来转换 JSON,在这里寻找一些输入。我正在尝试将所有级别中的所有项目放入一个数组中。 我的目标是获得一个包含所有项目的数组,而不知道我在json中有多少个级别。 这是我的输入和预期输出: 如果我有三个等级: 输入: 预期产出: 如果我有两个级别: 输入: 预期产出: 我试着写下这样的话: 结果为空,如果我单独运行每个转换,我会在适用时得到结果。你能帮我写一个简单的规

  • 我们正在考虑将flyway集成到我们的系统中,因为它似乎是以有效方式管理数据库迁移的绝佳工具。 然而,我不太确定如何继续: 我们有三个不同的数据库 < li >生产环境(MySQL) < li >测试环境(MySQL) < li >单元测试(H2内存中) 它们都包含不同的数据(不同的用户等)。数据库之间没有公共数据(在飞行路线页面上,这称为参考数据),只有结构应该保持不变。 看着网站,我的理解是这

  • 根据这个问题的答案,在第11行没有符合GC条件的对象;但是根据我的说法,至少有一个对象t2,它在第6行被设置为指向null,应该有资格进行垃圾回收。

  • 问题内容: 是否有一种(非破坏性的)方式列出缓冲通道中的所有元素? 我唯一能想到的就是循环所有这些,最后将它们重新插入。这似乎不是最聪明的方法。 链接到游乐场 问题答案: 从2011年开始,该线程在通道周围提供了一些包装程序,以启用Peek()函数,但这比其他任何方法都更可行。 总的结论是: 同步通道没有头(就像零长度切片) 你不能那样做,因为 a)它被放回队列的尾部而不是末端,并且 b)作家可能

  • 我正在尝试使用 Jolt 转换来转换 JSON,在这里寻找一些输入。我正在尝试将所有级别中的所有项目放入一个数组中。我的目标是获得一个包含所有项目的数组,而不知道我在 json 中有多少个级别。 这是我的输入和预期输出: 输入: 预期产出: 我的震动规格: 结果: 只有前4项包含id和foo,但并不是它们的foo值都只有一个。 你能告诉我怎么做对吗?