关于如何确保生成的 goroutine 在长时间运行的进程的上下文中正确“关闭”,我有一个基本的理解问题。我观看了有关该主题的讨论并阅读了有关最佳实践的内容。为了理解我的问题,请参阅视频“高级 Go 并发模式”here
对于以下内容,如果您在您的机器上运行代码,请导出环境变量 GOTRACEBACK=all 以便您能够在 panic 后看到例程状态。
我将原始示例的代码放在这里:naive (它不会在 go playground 上执行,我猜是因为使用了时间语句。请复制代码并在本地执行)
naive执行后panic的结果是
panic :给我看堆栈
协程 1 [正在运行]:
panic (0x48a680,0xc4201d8480)
/usr/lib/go/src/runtime/panic.go:500 +0x1a1
主.main()
/home/flx/workspace/go/go-rps/playground/ball-naive.go:18 +0x16b
goroutine 5 [chan receive]:
main.player(0x4a4ec4, 0x2, 0xc42006a060)
/home/flx/workspace/go/go-rps/playground/ball-naive.go:23 +0x61
由 main.main 创建
/home/flx/workspace/go/go-rps/playground/ball-naive.go:13 +0x76
goroutine 6 [chan receive]:
main.player(0x4a4ec6, 0x2, 0xc42006a060)
/home/flx/workspace/go/go-rps/playground/ball-naive.go:23 +0x61
由 main.main 创建
/home/flx/workspace/go/go-rps/playground/ball-naive.go:14 +0xad
退出状态 2
这证明了在系统上留下悬挂的 goroutines 的潜在问题,这对于长时间运行的进程尤其不利。
因此,根据我个人的理解,我尝试了两个稍微复杂一些的变体,这些变体可以在这里找到:
generator pattern with quit channel
(同样,在 playground 上不可执行,因为“处理时间太长”)
第一个解决方案由于各种原因不合适,甚至导致执行步骤的不确定性,具体取决于 goroutine 执行速度。
现在我想——问题终于来了! -- 使用退出 channel 的第二种解决方案适合在退出前从系统中消除所有执行痕迹。无论如何,“有时”程序退出得太快,并且 panic 报告一个额外的 goroutine runnable 仍然驻留在系统上。 panic 输出:
panic :显示堆栈
协程 1 [正在运行]:
panic (0x48d8e0,0xc4201e27c0)
/usr/lib/go/src/runtime/panic.go:500 +0x1a1
主.main()
/home/flx/workspace/go/go-rps/playground/ball-perfect.go:20 +0x1a9
goroutine 20 [可运行]:
main.player.func1(0xc420070060, 0x4a8986, 0x2, 0xc420070120)
/home/flx/workspace/go/go-rps/playground/ball-perfect.go:27 +0x211
由 main.player 创建
/home/flx/workspace/go/go-rps/playground/ball-perfect.go:36 +0x7f
退出状态 2
我的问题是:这不应该发生,对吧?在出现 panic 之前,我确实使用退出 channel 来清理状态。
我最后尝试在这里实现安全清理行为: artificial wait time for runnables to close
无论如何,该解决方案感觉不对,而且可能不适用于大量可运行对象?
确保正确清理的推荐和最惯用的模式是什么?
谢谢你的时间
最佳答案
你被输出愚弄了:你的“带退出 channel 的生成器模式”工作得很好,两个 goroutines 实际上 正确终止。
你在踪迹中看到它们是因为你太早 panic 了。记住:你必须让 goroutines 与 main 同时运行。 main 通过在 quit channel 上发出信号来“停止”这些 goroutines。在第 18 和 19 行的这两个发送之后,第 32 行的两个接收发生了。仅此而已!您仍然有三个 goroutines 正在运行:Main 在第 19 和 20 行之间,player goroutines 在第 32 和 33 行之间。如果现在 main 中的 panic 发生在 player 返回之前,那么 player goroutines 仍然存在并显示在 panic 中堆栈跟踪。如果只有调度程序有时间在第 33 行执行返回(它没有,因为你因 panic 而杀死它),这些 goroutine 会在几毫秒后结束。
这是“主要结束以尽早看到并发 goroutines 工作”问题的一个实例,这里每月问一次。您确实会看到并发的 goroutine 正在工作,但不是所有 都在工作。您可以尝试在 panic 之前休眠 2 毫秒,您的播放器 goroutine 将有时间执行返回,一切都很好。
关于go - 确保 goroutine 清理,最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39135348/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
我似乎经常遇到一些设计问题,但我不知道是什么是真的很合适。一方面我经常听到我应该限制耦合和坚持单一职责,但当我这样做时,我常常发现它很困难到在需要时将信息获取到程序的一部分。为了例如,classSingerdefinitialize(name)@name=nameendattr:nameend那么Song应该是:classSongdefnew(singer)@singer=singerendend或classSongdefnew(singer_name)@singer_name=singer_nameendend后者耦合性小,按道理应该用。但如果我以后发现宋有什么需要了解更多歌手,我的
我需要使用ActiveMerchant库在我们的一个Rails应用程序中设置支付解决方案。尽管这个问题非常主观,但人们对主要网关(BrainTree、Authorize.net等)的体验如何?它必须:处理定期付款。有能力记入个人帐户。能够取消付款。有办法存储用户的付款详细信息(例如Authotize.netsCIM)。干杯 最佳答案 ActiveMerchant很棒,但在过去一年左右的时间里,我在使用它时发现了一些问题。首先,虽然某些网关可能会得到“支持”——但并非所有功能都包含在内。查看功能矩阵以确保完全支持您选择的网关-http
我在Rails上使用带有ruby的solr。一切正常,我只需要知道是否有任何现有代码来清理用户输入,比如以?开头的查询。或* 最佳答案 我不知道执行此操作的任何代码,但理论上可以通过查看parsingcodeinLucene来完成并搜索thrownewParseException(只有16个匹配!)。在实践中,我认为您最好只捕获代码中的任何solr异常并显示“无效查询”消息或类似信息。编辑:这里有几个“sanitizer”:http://pivotallabs.com/users/zach/blog/articles/937-s
我有一个像这样的ruby散列{"stuff_attributes"=>{"1"=>{"foo"=>"bar","baz"=>"quux"},"2"=>{"foo"=>"bar","baz"=>"quux"}}}我想把它变成一个看起来像这样的散列{"stuff_attributes"=>[{"foo"=>"bar","baz"=>"quux"},{"foo"=>"bar","baz"=>"quux"}]}我还需要保留键的数字顺序,并且键的数量是可变的。上面是super简化的,但我在底部包含了一个真实的例子。执行此操作的最佳方法是什么?附言还需要递归就递归而言,这是我们可以假设的:1)
我正在使用ActiveAttr,它为您提供了很好的通过block选项进行初始化:person=Person.new()do|p|p.first_name='test'p.last_name='man'end但是,在包含ActiveAttr::Model的特定类中,我想绕过此功能,因为我想将该block用于其他用途。所以我们开始吧:classImperator::CommandincludeActiveAttr::ModelendclassMyCommand这失败得很惨,因为该block仍然向上传递到链中,并最终在ActiveAttr内部运行此代码:definitialize(*)sup