我是 Golang 初学者
我从 here. 读到关于 Go 中的并发性
在我收到关于 8th slide. 的问题之前,一切都很顺利
问题是:找出两个给定的二叉树是否等价。
我的方法:进行中序遍历,将两棵树的值保存在一个 slice 中并进行比较。
这是我的解决方案:[不完整]
package main
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
fmt.Println("executing first go routing")
Walk(t1, ch1)
fmt.Println("closing channel [ch1]")
close(ch1)
}()
go func() {
fmt.Println("executing second go routing")
Walk( t2, ch2 )
fmt.Println("closing channel [ch2]")
close(ch2)
}()
shouldContinue := true
var continue1, continue2 bool
for shouldContinue {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
continue1 = ok1
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
continue2 = ok2
}
shouldContinue = continue1 || continue2
}
return true
}
func main() {
Same(tree.New(1), tree.New(1))
}
我知道 goroutines 是协作调度的,如果一个 goroutine 正在循环或连续进行计算,它会完全阻塞另一个。所以我预计对于输出,它会首先从任一 channel 接收值,关闭它,然后它会从另一个 channel 接收值,然后关闭。一旦两者都关闭,for 循环就会中断。
令我惊讶的是,第一个 go 例程从未被安排好。这是我收到的输出:
executing second go routing
[ch2] [rcvd] 1
[ch2] [rcvd] 2
[ch2] [rcvd] 3
[ch2] [rcvd] 4
[ch2] [rcvd] 5
[ch2] [rcvd] 6
[ch2] [rcvd] 7
[ch2] [rcvd] 8
[ch2] [rcvd] 9
[ch2] [rcvd] 10
closing channel [ch2]
[ch2] [rcvd] 0
谁能解释一下这是怎么回事?一旦 channel2 关闭并且第二个 go 例程完成,为什么第一个不执行?
如有任何帮助,我们将不胜感激。谢谢。
更新:
我在谷歌上搜索了关于突破 channel 的问题,我发现了一个 SO 问题 here.
据此,我更新了我的解决方案如下:
package main
import (
"fmt"
"golang.org/x/tour/tree"
// "time"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
// time.Sleep(time.Millisecond)
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
fmt.Println("executing first go routing")
Walk(t1, ch1)
fmt.Println("closing channel [ch1]")
close(ch1)
}()
go func() {
fmt.Println("executing second go routing")
Walk( t2, ch2 )
fmt.Println("closing channel [ch2]")
close(ch2)
}()
for {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
if !ok1 {
ch1 = nil
}
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
if !ok2 {
ch2 = nil
}
}
if ch1 == nil && ch2 == nil {
break
}
}
return true
}
func main() {
Same(tree.New(1), tree.New(1))
}
这给出了我认为第一个片段的确切输出:
executing second go routing
[ch2] [rcvd] 1
[ch2] [rcvd] 2
[ch2] [rcvd] 3
[ch2] [rcvd] 4
[ch2] [rcvd] 5
[ch2] [rcvd] 6
[ch2] [rcvd] 7
[ch2] [rcvd] 8
[ch2] [rcvd] 9
[ch2] [rcvd] 10
closing channel [ch2]
[ch2] [rcvd] 0
executing first go routing
[ch1] [rcvd] 1
[ch1] [rcvd] 2
[ch1] [rcvd] 3
[ch1] [rcvd] 4
[ch1] [rcvd] 5
[ch1] [rcvd] 6
[ch1] [rcvd] 7
[ch1] [rcvd] 8
[ch1] [rcvd] 9
[ch1] [rcvd] 10
closing channel [ch1]
[ch1] [rcvd] 0
我现在对发生的事情更加困惑。
最佳答案
Once channel2 is closed, why doesn't the first one gets executed?
channel 不执行。一遍又一遍地执行的是您的选择。请注意,无论 channel 是否关闭,这两种情况都可以始终执行。所以 select 可以选择 id 所做的第二种情况,而你中止了。 (您的中止条件看起来可疑:一旦两个 channel 关闭,即如果两个 ok1 和 ok2 都为假,您就完成了)。
不要将 select 本身视为“goroutine 调度工具”。它不是。它将随机选择一个可运行案例。如果你所有的案例都是 val, ok := <- ch 的形式比所有都可运行和选择可能总是选择第二个。或者第一个,或者...
[Second Solution] I am now even more confused about what is going on.
您的中止条件不同。一旦两个 channel 都为零,您就会中断,这会在两个 channel 都关闭后发生。这与您的第一个解决方案不同,因为一旦任何 一个 channel 关闭,第一个解决方案就会中断。
这里并发的问题不在于 goroutine 调度,而在于执行选择的 for 循环的中止条件。它们不同于第一个和第二个,第一个从根本上是错误的,因为一旦任何 channel 耗尽它就会停止。
关于go - 意外的协程行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54233678/
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio
我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。
假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje
假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案
我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject
我正在尝试在ruby脚本中连接到服务器https://www.xpiron.com/schedule。但是,当我尝试连接时:require'open-uri'doc=open('https://www.xpiron.com/schedule')我收到以下错误消息:OpenSSL::SSL::SSLError:SSL_connectreturned=1errno=0state=SSLv2/v3readserverhelloA:sslv3alertunexpectedmessagefrom/usr/local/lib/ruby/1.9.1/net/http.rb:678:in`conn
defreverse(ary)result=[]forresult[0,0]inaryendresultendassert_equal["baz","bar","foo"],reverse(["foo","bar","baz"])这行得通,我想了解原因。有什么解释吗? 最佳答案 如果我使用each而不是for/in重写它,它看起来像这样:defreverse(ary)result=[]#forresult[0,0]inaryary.eachdo|item|result[0,0]=itemendresultendforainb基本上就
在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol