<p>So, I have this package: <a href="https://github.com/nubunto/ports" rel="nofollow">https://github.com/nubunto/ports</a>
Basically, a test that provides an API for a interface in Go to a external program.
There's a test in there.
That test is failing, with a deadlock.
Any insights on the why?</p>
<p>Thanks in advance, reddit gophers.</p>
<hr/>**评论:**<br/><br/>skidooer: <pre><p>Your <code>Launch</code> function returns an error, which results in the inner goroutine not being executed. Then, when you try to read from the channel, with no other goroutines operating, you are effectively doing this:</p>
<pre><code>func main() {
ch := make(chan int)
<-ch // deadlock
}
</code></pre>
<p>One way to fix this is:</p>
<pre><code>diff --git a/ports_test.go b/ports_test.go
index 7d4c47f..76ae1c0 100644
--- a/ports_test.go
+++ b/ports_test.go
@@ -18,6 +18,7 @@ func TestLaunch(t *testing.T) {
err := Launch(test.program, ch)
if err != nil {
t.Errorf("launch returned error: %v\n", err)
+ continue
}
ret := <-ch
if !bytes.Equal(test.expected, ret) {
</code></pre></pre>Logiraptorr: <pre><p>To elaborate on <a href="/u/skidooer" rel="nofollow">/u/skidooer</a>'s answer:</p>
<p>Launch returns the error <code>fork/exec echo "hello world": no such file or directory</code>. </p>
<p>This is because you're passing <code>echo "hello world"</code> as the <code>Path</code> field to the exec.Command. The exec package expects that to be the path to an <em>executable</em>, not including any arguments to the executable. To fix this, you'll have to pass arguments separately as the Args field. See: <a href="https://golang.org/pkg/os/exec/#Cmd" rel="nofollow">exec.Cmd</a>. </p>
<p>Now more general comments:</p>
<ul>
<li><p>It is probably more useful to make Launch take arguments as a separate parameter. You can see in the Cmd struct docs above that the intended way to use it is to call <code>exec.Command</code>, passing both the path and args. You can then set fields on the returned value if you need to customize things. </p></li>
<li><p>It may just be a prototype, but in this example you're passing a bytes.Buffer as both stdout and stderr. If all you want is to get both output streams as a byte buffer, you can use <a href="https://golang.org/pkg/os/exec/#Cmd.CombinedOutput" rel="nofollow"><code>Cmd.CombinedOutput</code></a>. This will start the program as well as collect the output for you.</p></li>
<li><p>In general, it's unusual to use channels in the way you are doing here. Typically, if a function starts a go routine and wants to communicate about its status later, it will create it's own channel internally and return it. In your case specifically, it would not be clear to me that Launch closes the channel passed as the second argument. However, if Launch creates the channel, then Launch is the "owner" so to speak, and I would expect it to close the channel at some point in the future.</p></li>
</ul>
<p>I hope you found this useful. Here is a sample of how I might change this code as it is now (without knowing what the long term plan is). <a href="https://play.golang.org/p/QgeOW8Dl2T" rel="nofollow">ports.go</a>, <a href="https://play.golang.org/p/IqAGnNFCFU" rel="nofollow">ports_test.go</a></p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传