草庐IT

multithreading - 自同步 Goroutines 以死锁告终

coder 2024-07-11 原文

我有一个压力测试问题,想通过 Go 中的简单同步来解决。到目前为止,我已经尝试查找关于我在 Go 中同步的特定用例的文档,但没有找到合适的文档。

更具体一点: 我必须完成一项任务,我必须在主例程中启动大量线程(在此示例中仅使用两个线程进行说明)。所有被启动的worker都应该以无序的方式自己准备一些初始化 Action 。直到它们到达一个小的命令序列,我希望所有的 goroutines 一次执行它们,这就是为什么我想要让 goroutines 相互同步。对我的任务来说非常重要的是,通过实例化所有其他 goroutine 的主例程的延迟不会影响工作人员执行的真正并行性(在注释中的标签#maximum parallel 处)。为此,我确实使用主例程中运行的 goroutines 的数量初始化了一个 WaitGroup ,并将其传递给所有例程,以便它们可以同步彼此的工作流。

代码看起来类似于这个例子:

import sync

func worker_action(wait_group *sync.WaitGroup) {
    // ...
    // initialization
    // ...

    defer wait_group.Done() 
    wait_group.Wait() // #label: wait

    // sequence of maximum parallel instructions // #label: maximum parallel

    // ...
}

func main() {
    var numThreads int = 2 // the number of threads shall be much higher for the actual stress test

    var wait_group sync.WaitGroup
    wait_group.Add(numThreads)
    for i := 0; i < numThreads; i++ {
        go worker_action(&wait_group)
    }

    // ...
}

不幸的是,一旦所有 goroutine 都到达 Wait 指令(在注释中标有#wait),我的设置就会陷入僵局。对于我从主例程开始的任何数量的线程都是如此(即使是两个线程也会立即陷入死锁)。

从我的角度来看,死锁不应该发生,因为在等待指令之前,每个 goroutine 都会在同一个 WaitGroup 上执行 done 函数。

我是否对 WaitGroup 的工作方式有错误的理解?例如,是否不允许在主例程以外的 goroutine 内部执行等待函数?或者有人可以提示我还缺少什么吗?

非常感谢您。

编辑:

非常感谢@tkausl。确实是不必要的“延迟”导致了问题。我不知道我自己怎么看不到。

最佳答案

您的代码中存在多个问题。首先是表格。地道的 Go 应该使用驼峰命名法。 wg 是 WaitGroup 的更好名称。

但更重要的是在代码等待的地方使用。不在你的 Goroutine 中。它应该在主函数中等待:

func workerAction(wg *sync.WaitGroup) {
    // ...
    // initialization
    // ...

    defer wg.Done() 
    // wg.Wait() // #label: wait

    // sequence of maximum parallel instructions // #label: maximum parallel

    // ...
}

func main() {
    var numThreads int = 2 // the number of threads shall be much higher for the actual stress test

    var wg sync.WaitGroup
    wg.Add(numThreads)
    for i := 0; i < numThreads; i++ {
        go workerAction(&wg)
    }
    wg.Wait() // you need to wait here

    // ...
}

关于multithreading - 自同步 Goroutines 以死锁告终,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53127050/

有关multithreading - 自同步 Goroutines 以死锁告终的更多相关文章

  1. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  2. ruby - 使用 SizedQueue 在 ruby​​ 代码中出现死锁 - 2

    我认为我对线程在ruby​​中的工作原理存在根本性的误解,我希望获得一些见解。我想要一个简单的生产者和消费者。首先,生产者线程从文件中提取行并将它们粘贴到SizedQueue中;当那些用完时,在末端贴上一些token,让消费者知道事情已经完成。require'thread'numthreads=2filename='edition-2009-09-11.txt'bq=SizedQueue.new(4)producerthread=Thread.new(bq)do|queue|File.open(filename)do|f|f.eachdo|r|queue现在有几个消费者。为简单起见,让

  3. ruby-on-rails - 本地 yaml key 的 i18n 同步 - 2

    类似的问题,但对于java,Keepingi18nresourcessynced如何保持i18nyamllocals的key同步?即,当将key添加到en.yml时,如何将它们添加到nb.yml或ru.yml?如果我在my_title:"atitle"旁边添加键my_label:"sometextinenglish"我想把它给我的其他本地人我指定,因为我不能做所有的翻译,它应该回到其他语言的英语例如en.ymlsomegroup:my_tile:"atitleinenglish"my_label:"sometextinenglish"othergroup:...我想发出命令,将整个键和

  4. FIFO实战学习-同步FIFO/异步FIFO-格雷码 - 2

    目录FIFO一.自定义同步FIFO1.1代码设计1.2Testbech1.3行为仿真***学习位宽计算函数$clog2()***$clog2()系统函数使用,可以不关注***分布式资源或者BLOCKBRAM二.异步FIFO2.1在FIFO判满的时候有两种方式:2.2异步FIFO为什么要使用格雷码2.2.1介绍格雷码2.2.2格雷码在异步FIFO中的应用2.2.2格雷码判满2.4二进制与格雷码之间的转换2.4.1二进制码转换为格雷码的方法2.4.2格雷码转换为二进制码的方法2.3实现框图2.5实现及仿真代码2.6仿真图验证2.7结论FIFO  这篇更多的是记录FIFO学习,参考了众多优秀的文章,

  5. ruby - 是什么导致我的 Ruby `trap` block 出现这种死锁? - 2

    我正在通读JesseStorimer的优秀著作,WorkingwithUnixProcesses.在有关从已退出的子进程捕获信号的部分中,他提供了一个代码示例。我稍微修改了该代码(见下文)以更清楚地了解正在发生的事情:父级在信号之间恢复自己的执行(我可以通过它的puts看到),wait在一个trap语句中为多个child执行(有时我得到“收到CHLD信号”,然后是多个“childpid退出”)。预期输出通常下面代码的输出类似于:parentisworkinghardReceivedaCHLDsignalchildpid73408exitedparentisworkinghardpare

  6. ruby - 如何跟踪 Ruby 中的死锁 - 2

    我使用BrB为我用Process#forkfork的Ruby1.9中的各种工作进程共享数据源:Thread.abort_on_exception=trueforkdoputs"Initializingdatasourceprocess...(PID:#{Process.pid})"data=DataSource.new(files)BrB::Service.start_service(:object=>data,:verbose=>false,:host=>host,:port=>port)EM.reactor_thread.joinendworkerfork如下:8.timesdo|

  7. DolphinScheduler 调度 DataX 实现 MySQL To ElasticSearch 增量数据同步实践 - 2

    数据同步的方式数据同步的2大方式基于SQL查询的CDC(ChangeDataCapture):离线调度查询作业,批处理。把一张表同步到其他系统,每次通过查询去获取表中最新的数据。也就是我们说的基于SQL查询抽取;无法保障数据一致性,查的过程中有可能数据已经发生了多次变更;不保障实时性,基于离线调度存在天然的延迟;工具软件以Kettle(ApacheHop最新版)、DataX为代表,需要结合任务调度系统使用。基于日志的CDC:实时消费日志,流处理,例如MySQL的binlog日志完整记录了数据库中的变更,可以把binlog文件当作流的数据源;保障数据一致性,因为binlog文件包含了所有历史变更

  8. ruby - 如何修复 Ruby 中 join() 中的死锁 - 2

    我在Ruby中从事多线程工作。代码片段是:threads_array=Array.new(num_of_threads)1.upto(num_of_threads)do|i|Thread.abort_on_exception=truethreads_array[i-1]=Thread.new{catch(:exit)doprint"s#{i}"user_id=nilloopdouser_id=user_ids.pop()ifuser_id==nilprint"a#{i}"Thread.stop()enddosomething(user_id)endend}end#puts"aftert

  9. ruby - 线程池中的死锁 - 2

    我找不到适合Ruby的ThreadPool实现,所以我写了我的(部分基于这里的代码:http://web.archive.org/web/20081204101031/http://snippets.dzone.com:80/posts/show/3276,但更改为等待/信号和ThreadPool关闭的其他实现。但是在运行一段时间后(有100个线程并处理大约1300个任务),它在第25行死锁-它在那里等待新工作。任何想法,为什么会发生?require'thread'beginrequire'fastthread'rescueLoadError$stderr.puts"Usingther

  10. 【Unity】Unity 欧拉角、四元数、万向节死锁、四元数转轴角 - 2

    文章目录欧拉角(Euler)万向节欧拉角旋转特性欧拉角优点欧拉角缺点方位的表达方式不唯一万向节锁(GimbalLock)四元数(Quaternion)四元数转轴角四元数优点四元数缺点Quaternion类欧拉角(Euler)什么是欧拉角?百科上是这样解释的:用来确定定点转动刚体位置的3个一组独立角参量,由章动角θ、旋进角(即进动角)ψ和自转角φ组成,为欧拉首先提出而得名。很难理解吧?其实我们没有必要把欧拉角想得太复杂。对于开发者来说,欧拉角就是用一个Vector3变量来记录物体沿着x、y、z轴的旋转。注意,虽然这是一个Vector3变量,但它并不是向量,这个变量的x、y、z三个分量是用来描述旋

随机推荐