<p>I've just started looking at go a few days ago, and I wanted to try rewriting an unwieldy set of python scripts that I have, in go.</p>
<p>The object of the code is to read some files from Amazon S3, and process them line by line.</p>
<p>This is a function I wrote, using the AWS GO SDK, to list a bucket, and return them in a channel. I'm using channels to emulate python's generators, since the list can be very large</p>
<pre><code>func ListS3(bucket, prefix string, client *s3.S3) chan string{
c := make(chan string)
input := s3.ListObjectsInput{
Bucket: aws.String(bucket),
Prefix: aws.String(prefix)}
go func() {
client.ListObjectsPages(
&input,
func(p *s3.ListObjectsOutput, last bool) (shouldContinue bool) {
for _, obj := range p.Contents{
c <- *obj.Key
}
if last {
close(c)
}
return true
})
}()
return c
}
</code></pre>
<p>And I'm using the function like this:</p>
<pre><code>list := ListS3(bucket, path, svc)
for key := range list {
fmt.Println(key)
}
</code></pre>
<hr/>**评论:**<br/><br/>dotaheor: <pre><p>Is client.ListObjectsPages a synced or asycned call?
If it is a synced call, please put close(c) after it, for it is possible the callback passed to client.ListObjectsPages will never be called so that close(c) will be never called.</p></pre>ilogik: <pre><p>fair point, I've added it</p></pre>Epolevne: <pre><p>If in your usage it's important to know that you got all the items then I would suggest adding some error handling since this is a network operation and will fail at some point. The current code may not return all the items of the S3 bucket and the caller cannot tell.</p></pre>ilogik: <pre><p>ListObjectsPages returns an error object. I'm not really sure how I'm supposed to pass that back, since it's being called in a goroutine.</p>
<p>I had started by adding a second error return value to ListS3, but that doesn't make sense, because that only returns the channel, which happens immediately.</p>
<p>Should I return the err through the channel?</p>
<p>Do you have any examples code for this?</p></pre>Epolevne: <pre><p>You could use a struct on the channel that has an error and a string instead of just a string. </p></pre>danredux: <pre><p>Never start a goroutine without a plan to end it. If something goes wrong while iterating, the goroutine will stay forever. That's a leak.</p></pre>Veonik: <pre><p>I'd say this is valid. The <a href="https://golang.org/src/text/template/parse/lex.go#L146" rel="nofollow">text/template package's lexer</a> does much the same, emitting a token via a channel to the parser as it reads them.</p></pre>jerf: <pre><p>The usage you have literally given us above is not "invalid", but it is a useless use of channels. You could just as easily put the Println in the callback in directly.</p>
<p>However, if you spawn a set of worker goroutines who all read from that channel and then do the work for the given bucket, you'd have something useful. In this case you see why most Go network APIs are written to be synchronous; it keeps the code simple, and users of those APIs can easily add any other asynchronous/concurrent behaviors they want via goroutines.</p></pre>ilogik: <pre><p>Yes, that's the plan, to have workers processing the the resulting files.</p></pre>jerf: <pre><p>Cool, just wanted to be sure. It is not uncommon to see code posted by relatively new Go programmers that uselessly uses channels or spawns goroutines to worse than no effect. :)</p></pre>ilogik: <pre><p>that's exactly why I posted the question. I was mostly just using it as a replacement for generators for now.</p>
<p>I've picked this problem as my first go program because I thought it was a good use case for goroutines</p></pre>Yojihito: <pre><p>Do you need a code sample of a worker pool listening on a channel and doing func_x()?</p>
<p>I've done that for my last project, works quite well.</p></pre>ilogik: <pre><p>yeah, I'd love that :)</p></pre>Yojihito: <pre><p><a href="https://play.golang.org/p/QnU1zOZrHJ" rel="nofollow">https://play.golang.org/p/QnU1zOZrHJ</a></p></pre>Morgahl: <pre><p>Small critique. Use a for range loop on the channel if there is only one channel you are listening to:</p>
<p><a href="https://play.golang.org/p/xihPx1RWMb" rel="nofollow">https://play.golang.org/p/xihPx1RWMb</a></p>
<p>This allows you to to close the channel, the workers will finish processing the workQueue and then exit. Always write your Goroutines with a way to exit when they are done :)</p></pre>ilogik: <pre><p>awesome!, thank you :)</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传