<p>TLDR Problem: I want to design an API call that does something asynchronously and I'm unsure about the best practice way to do this.</p>
<hr/>
<p>Say the API I want to expose is a function TimeConsumingTask(), which eventually returns a TaskResult. My first inclination would be to write something like:</p>
<pre><code>func TimeConsumingTask() (chan TaskResult, chan error)
</code></pre>
<p>where the first return value is a 'done' channel and the second return value is an 'error' channel. I'm unsure if TimeConsumingTask should close both channels when it finishes.</p>
<p>Alternatively I could do:</p>
<pre><code>func TimeConsumingTask(chan TaskResult, chan error)
</code></pre>
<p>But should they be pointers?</p>
<p>Both approaches so far assume that TimeConsumingTask will spin off goroutines on its own so it can return quickly.</p>
<p>However, I don't see why the API couldn't be that clients have to call 'go TimeConsumingTask(done, error)'?</p>
<p>Any ideas that I'm missing?</p>
<p>EDIT: I might want to run 100 TimeConsumingTasks and then wait for them all to be done. Perhaps a WaitGroup parameter or can this be implemented with some kind of slice of 'done' channels?</p>
<hr/>**评论:**<br/><br/>chrj: <pre><p>Let the caller handle this. Just block and if that's a problem for the caller, he will goroutine it himself.</p></pre>scottious: <pre><p>Though I still need to choose a way for the long running process to communicate back a result if it is run asynchronously, right?</p>
<p>Like, if I had a signature of:</p>
<pre><code>func TimeConsumingTask() TaskResult
</code></pre>
<p>then I call it as:</p>
<pre><code>go TimeConsumingTask()
</code></pre>
<p>then how do I get the return value?</p></pre>TheMerovius: <pre><p>That is not your problem, it's the problem of your caller. They need to wrap it in a channel themselves.</p>
<p>If you are in doubt about this being the best way to go about it, consider that that's exactly what <a href="https://godoc.org/net/http#Client" rel="nofollow">net/http.Client</a> does.</p>
<p>The only additional tidbit I'd have is, that you should add a <a href="https://godoc.org/golang.org/x/net/context#Context" rel="nofollow">context.Context</a> as a parameter and implement cancellation too.</p></pre>scottious: <pre><p>Gotcha, that actually makes a lot of sense. I'm still new to Go :)</p></pre>chrj: <pre><p>If you need to further process the result from the task, just embed that in the goroutine as well:</p>
<pre><code>go func() {
res := TimeConsumingTask()
handleResult(res)
}()
</code></pre>
<p>If the caller needs to coordinate further processing outside the goroutine, they can use wait groups and channels to take care of timing and pass the result around.</p></pre>sc28: <pre><p>You might want to read this:</p>
<p><a href="https://blog.golang.org/context" rel="nofollow">https://blog.golang.org/context</a></p>
<p>Good information regarding context, cancellation, etc.</p></pre>Matthias247: <pre><p>I would only use one result channel for errors and success, where I don't necessarily care whether it's from the caller or the called.</p>
<p>However I would also add one cancellation channel as an input parameter, that the caller can also in order to signal to the long running task that the result is no longer necessary. The long running task can then select {} between this cancellation channel and the result channel for delivering the result and thereby won't deadlock if there is no reader.</p>
<p>If the result is not a resource that anybody has to care about using only a buffered return channel instead of providing cancellation would also be an option. But it would use more resources if you often start those long running operations and at a later point of time decide that you don't need them anymore and just ignore the result (leaving the tasks further running) instead of canceling them.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传