Help needed: A func that is optionally a goroutine and returns an error

xuanbao · · 516 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hey! I&#39;m fairly new to golang, and I&#39;m a bit confused on an elegant way to do the following in golang.</p> <p>I want to create a function that is optionally a goroutine, but I want it to be able to return errors. The initial way I tried to solve this problem was an error channel. </p> <pre><code>func optionalRoutine(stuff int, errChan chan&lt;- error){ defer close(errChan) // do stuff errChan &lt;- err } </code></pre> <p>But, this leads to a deadlock if not run in a goroutine because there err is waiting to send.</p> <pre><code>go optionalRoutine(0, errChan) // works optionalRoutine(0, errChan) // doesn&#39;t work </code></pre> <p>So, I think anything to do with channels is out of the question. I could pass in a pointer to an error that gets set by the function if there is an error, but I don&#39;t really understand how to detect if the function is done. I could use the sync package&#39;s waitgroup, but I don&#39;t know if there is a better solution.</p> <p>Thanks in advance for the help!</p> <hr/>**评论:**<br/><br/>binaryblade: <pre><p>Have it just return the error for when you want to call it directly. Then when you need a go routine just wrap it in a lambda that handles the channel stuff.</p></pre>intermernet: <pre><p>Quick example:</p> <pre><code>package main import &#34;fmt&#34; func f() (int, error) { return 1, fmt.Errorf(&#34;This is an error&#34;) } func main() { // As a normal function i, err := f() fmt.Println(i, err) // As a goroutine ic := make(chan int) ec := make(chan error) go func() { i, err := f() ic &lt;- i ec &lt;- err }() fmt.Println(&lt;-ic, &lt;-ec) } </code></pre> <p><a href="http://play.golang.org/p/BO_qF2qELh" rel="nofollow">playground</a></p></pre>earthboundkid: <pre><p>Your example requires the answer channel to send before the error channel can. I&#39;d probably change it a little so you can receive in any order. Or maybe don&#39;t send a value if the error is non-nil. </p></pre>intermernet: <pre><p>True, it would be better to only send the error if it was non-nil, then have a select statement to receive.</p></pre>earthboundkid: <pre><p>Right, or send a struct that acts a value, error type.</p> <p><a href="http://play.golang.org/p/OcV6ROurjk" rel="nofollow">http://play.golang.org/p/OcV6ROurjk</a></p></pre>tv64738: <pre><p>Rule of thumb: Write synchronous APIs, let the caller be in charge of concurrency.</p> <p>You can use concurrency inside the API, but don&#39;t expose details in the API unnecessarily. (Necessary exception: when you know caller will want to integrate the call into a <code>select{}</code>.)</p></pre>lespritd: <pre><p>The easiest thing to do is to use your code you have but instantiate the channel with a size of 1</p> <p><a href="http://play.golang.org/p/cBDXtett8N" rel="nofollow">http://play.golang.org/p/cBDXtett8N</a></p></pre>atishpatel2012: <pre><p>This solution seems to be the best in my opinion. And, I can check for the capacity of the errchan to ensure one with size 1 is passed in. Thank you again!</p></pre>egonelbre: <pre><p>Create the code as:</p> <pre><code> func doStuff(stuff int) error { </code></pre></pre>FiveRoundsRapid: <pre><p>Many sensible suggestions here. You could also have it accept a channel as an argument, but pass nil to it when not a goroutine, e.g.:</p> <pre><code>func optionalRoutine(errChan chan error) error { // do stuff if errChan != nil { errChan &lt;- err } return err } func main() { err1 := optionalRoutine(nil) errChan := make(chan error) go optionalRoutine(errChan) err2 := &lt;- errChan } </code></pre></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

516 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传