FAQ
I have read the spec on the use of the keyword range:
http://golang.org/ref/spec#RangeClause

Using this code as a reference for my questions:

func Range() {

     for _, value := range data {

         Foo(value)

     }

}


func Index() {

     for index := 0; index < len(data); index++ {

         Foo(data[index])

     }

}


Shouldn't using an index to access each value from a slice be more
efficient than using a for-range and creating a copy. Especially if value
is based on a user-defined type with a few fields?

What is the advantage of using for-range over using a for with an index?

Is the answer that the for-range is simpler, and less error prone. Plus it
eliminates the bounds checking that Go is executing with each call to
data[index]?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Dave Cheney at Apr 10, 2014 at 6:25 am
    You're assuming that all copying is bad. I do not believe this is true.

    Some copying may be bad if you have a massive struct say,

    var v []struct{[1000]int64}

    but in general I think people get too hot under the collar about copying.

    Don't forget a slice header is 3 words and is always copied on function
    calls and the like, that's 24 bytes on amd64, 37% of a cache line.

    Dave
    On Thursday, 10 April 2014 15:59:49 UTC+10, William Kennedy wrote:

    I have read the spec on the use of the keyword range:
    http://golang.org/ref/spec#RangeClause

    Using this code as a reference for my questions:

    func Range() {

    for _, value := range data {

    Foo(value)

    }

    }


    func Index() {

    for index := 0; index < len(data); index++ {

    Foo(data[index])

    }

    }


    Shouldn't using an index to access each value from a slice be more
    efficient than using a for-range and creating a copy. Especially if value
    is based on a user-defined type with a few fields?

    What is the advantage of using for-range over using a for with an index?

    Is the answer that the for-range is simpler, and less error prone. Plus it
    eliminates the bounds checking that Go is executing with each call to
    data[index]?
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Caleb Spare at Apr 10, 2014 at 6:34 am
    It's impossible to make blanket statements about optimizations like
    this. It depends on many factors, including:

    - The types of slices you're using
    - Hardware peculiarities
    - Optimizations in the Go compiler you're using (which change as it matures)

    This case is absolutely not worth "optimizing" in the general case;
    only if it's provably a bottleneck in a very tight loop should you
    even spend any time thinking about it.

    In that case, testing.B is your friend.

    Here is a simple benchmark in which the range version is faster than
    the index version, BUT only for

    - my computer and Go compiler
    - a particular workload (a running sum)
    - a particular slice type ([]int)

    http://play.golang.org/p/YikjtG7dXO

    I make no claims about the general relative performance of for/range
    vs traditional for.

    -Caleb

    On Wed, Apr 9, 2014 at 10:59 PM, William Kennedy
    wrote:
    I have read the spec on the use of the keyword range:
    http://golang.org/ref/spec#RangeClause

    Using this code as a reference for my questions:

    func Range() {

    for _, value := range data {

    Foo(value)

    }

    }


    func Index() {

    for index := 0; index < len(data); index++ {

    Foo(data[index])

    }

    }


    Shouldn't using an index to access each value from a slice be more efficient
    than using a for-range and creating a copy. Especially if value is based on
    a user-defined type with a few fields?

    What is the advantage of using for-range over using a for with an index?

    Is the answer that the for-range is simpler, and less error prone. Plus it
    eliminates the bounds checking that Go is executing with each call to
    data[index]?

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • William Kennedy at Apr 10, 2014 at 12:25 pm

    On Apr 10, 2014, at 2:33 AM, Caleb Spare wrote:

    It's impossible to make blanket statements about optimizations like
    this. It depends on many factors, including:

    - The types of slices you're using
    - Hardware peculiarities
    - Optimizations in the Go compiler you're using (which change as it matures)

    This case is absolutely not worth "optimizing" in the general case;
    only if it's provably a bottleneck in a very tight loop should you
    even spend any time thinking about it.

    In that case, testing.B is your friend.

    Here is a simple benchmark in which the range version is faster than
    the index version, BUT only for

    - my computer and Go compiler
    - a particular workload (a running sum)
    - a particular slice type ([]int)

    http://play.golang.org/p/YikjtG7dXO

    I make no claims about the general relative performance of for/range
    vs traditional for.

    -Caleb
    So maybe my question was too generic, but I was curious if there was more to this than meets the eye. If I don't ask, I can't learn.

    I was not attempting for anyone to make a blanket statement. I also created benchmarks where range performed better. Your example is much better, thanks.

    I was hoping for answers like Dave's. I have been thinking lately about how mechanical sympathy for the Go runtime, OS and hardware should play a role in the code we write.

    I have clients who are selling products with features I haven't even coded yet. My timeframes are ridiculous and I always need to get something out quickly that is solid and performs. I don't always have time to benchmark everything or make fine-tuned decisions. I think this is the reality for a lot of people. Go has made this situation much better for me.

    The more I learn, I realize that if I write idiomatic Go and follow good form, I get a lot of mechanical sympathy out of the box. I am learning that the go dev team has already incorporated mechanical sympathy into the language and runtime. Go does not put performance ahead of other things, such as fast compile times and safer code, yet the performance is there. I can trust these things and when I have time, benchmark and refactor later.

    I was just looking for guidance on what was good form in this particular generic example. I think you both answered the question for me. Thanks.
    On Wed, Apr 9, 2014 at 10:59 PM, William Kennedy
    wrote:
    I have read the spec on the use of the keyword range:
    http://golang.org/ref/spec#RangeClause

    Using this code as a reference for my questions:

    func Range() {

    for _, value := range data {

    Foo(value)

    }

    }


    func Index() {

    for index := 0; index < len(data); index++ {

    Foo(data[index])

    }

    }


    Shouldn't using an index to access each value from a slice be more efficient
    than using a for-range and creating a copy. Especially if value is based on
    a user-defined type with a few fields?

    What is the advantage of using for-range over using a for with an index?

    Is the answer that the for-range is simpler, and less error prone. Plus it
    eliminates the bounds checking that Go is executing with each call to
    data[index]?

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • William Kennedy at Apr 10, 2014 at 1:23 pm
    Caleb, I think I may have come across ungrateful with my tone and if I did I am sorry. Your answer was very good as well, not just Dave's. I appreciate your time and thoughts on the subject.

    The book, my work and people coming to me with questions has me constantly thinking about the language. Maybe thinking about things like mechanical sympathy is old school but this is a new idea for me and it just resonated. I think it helps me focus and teach people to focus on learning idiomatic Go and using good form. I just get confused sometimes when I look at examples like the one I presented. Your answer is exactly the kind of feedback I was looking for. Thank and sorry if my response didn't seem greatful.

    -Bill

    On Apr 10, 2014, at 8:24 AM, William Kennedy wrote:


    On Apr 10, 2014, at 2:33 AM, Caleb Spare wrote:

    It's impossible to make blanket statements about optimizations like
    this. It depends on many factors, including:

    - The types of slices you're using
    - Hardware peculiarities
    - Optimizations in the Go compiler you're using (which change as it matures)

    This case is absolutely not worth "optimizing" in the general case;
    only if it's provably a bottleneck in a very tight loop should you
    even spend any time thinking about it.

    In that case, testing.B is your friend.

    Here is a simple benchmark in which the range version is faster than
    the index version, BUT only for

    - my computer and Go compiler
    - a particular workload (a running sum)
    - a particular slice type ([]int)

    http://play.golang.org/p/YikjtG7dXO

    I make no claims about the general relative performance of for/range
    vs traditional for.

    -Caleb
    So maybe my question was too generic, but I was curious if there was more to this than meets the eye. If I don't ask, I can't learn.

    I was not attempting for anyone to make a blanket statement. I also created benchmarks where range performed better. Your example is much better, thanks.

    I was hoping for answers like Dave's. I have been thinking lately about how mechanical sympathy for the Go runtime, OS and hardware should play a role in the code we write.

    I have clients who are selling products with features I haven't even coded yet. My timeframes are ridiculous and I always need to get something out quickly that is solid and performs. I don't always have time to benchmark everything or make fine-tuned decisions. I think this is the reality for a lot of people. Go has made this situation much better for me.

    The more I learn, I realize that if I write idiomatic Go and follow good form, I get a lot of mechanical sympathy out of the box. I am learning that the go dev team has already incorporated mechanical sympathy into the language and runtime. Go does not put performance ahead of other things, such as fast compile times and safer code, yet the performance is there. I can trust these things and when I have time, benchmark and refactor later.

    I was just looking for guidance on what was good form in this particular generic example. I think you both answered the question for me. Thanks.
    On Wed, Apr 9, 2014 at 10:59 PM, William Kennedy
    wrote:
    I have read the spec on the use of the keyword range:
    http://golang.org/ref/spec#RangeClause

    Using this code as a reference for my questions:

    func Range() {

    for _, value := range data {

    Foo(value)

    }

    }


    func Index() {

    for index := 0; index < len(data); index++ {

    Foo(data[index])

    }

    }


    Shouldn't using an index to access each value from a slice be more efficient
    than using a for-range and creating a copy. Especially if value is based on
    a user-defined type with a few fields?

    What is the advantage of using for-range over using a for with an index?

    Is the answer that the for-range is simpler, and less error prone. Plus it
    eliminates the bounds checking that Go is executing with each call to
    data[index]?

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
    To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/V_03s9ClyJs/unsubscribe.
    To unsubscribe from this group and all its topics, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Simon place at Apr 11, 2014 at 2:25 am
    been there, my conclusion,(after i came here asking as well), was to just
    use range when possible and wait for optimisation.

    basically i think the index loop has potentially more complexity, firstly
    index might be changed in the loop, and so the test will be needed each
    time, compiler complexity for checking index cant be changed in the loop,
    anywhere in potentially a long piece of code, might not be worth it, the
    simpler form of range allows more straightforward optimisation.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Andy Balholm at Apr 11, 2014 at 4:12 pm
    If you're worried about the value being copied, you can use the
    single-valued form of range (for i := range data). That should have all the
    advantages (if any) of the for i := 0 version, and still be able to avoid
    bounds checks.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Henrik Johansson at Apr 11, 2014 at 6:46 pm
    Really? The range notation with indexing avoids bounds checks?


    On Fri, Apr 11, 2014 at 6:12 PM, Andy Balholm wrote:

    If you're worried about the value being copied, you can use the
    single-valued form of range (for i := range data). That should have all the
    advantages (if any) of the for i := 0 version, and still be able to avoid
    bounds checks.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • William Kennedy at Apr 11, 2014 at 6:58 pm

    On Apr 11, 2014, at 2:46 PM, Henrik Johansson wrote:

    Really? The range notation with indexing avoids bounds checks?
    I think Andy was trying to say that you can use the range to get an index and not worry about when to end the for loop. Range takes care of that internally for you. Obviously you need to use the index to select a specific element from the slice. That operation would require a bounds check.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Henrik Johansson at Apr 11, 2014 at 7:00 pm
    Ah cool!

    I thought I have misunderstood something fundamental.

    Thanks!

    On Fri, Apr 11, 2014 at 8:58 PM, William Kennedy wrote:
    On Apr 11, 2014, at 2:46 PM, Henrik Johansson wrote:

    Really? The range notation with indexing avoids bounds checks?
    I think Andy was trying to say that you can use the range to get an index
    and not worry about when to end the for loop. Range takes care of that
    internally for you. Obviously you need to use the index to select a
    specific element from the slice. That operation would require a bounds
    check.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Andy Balholm at Apr 12, 2014 at 5:30 am

    On Apr 11, 2014, at 11:46 AM, Henrik Johansson wrote:

    Really? The range notation with indexing avoids bounds checks?
    I was wrong. It generates exactly the same code as for i := 1; i < len(s); i++.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Dan Kortschak at Apr 12, 2014 at 7:44 am
    More realistically i, l := 0, len(s); i < l; i++
    On 12/04/2014, at 3:00 PM, "Andy Balholm" wrote:

    I was wrong. It generates exactly the same code as for i := 1; i < len(s); i++.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Andy Balholm at Apr 13, 2014 at 5:40 pm
    Well, starting with 0 anyway! :-( I should have copied directly from my working code.

    But if you replace that 1 with a 0, the assembly output is actually identical to for i := range s
    On Apr 12, 2014, at 12:44 AM, Dan Kortschak wrote:

    More realistically i, l := 0, len(s); i < l; i++
    On 12/04/2014, at 3:00 PM, "Andy Balholm" wrote:

    I was wrong. It generates exactly the same code as for i := 1; i < len(s); i++.



    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Dan Kortschak at Apr 12, 2014 at 7:56 pm
    There's more different there than the initial value.

    http://play.golang.org/p/T52dPKs63A
    http://play.golang.org/p/wMZoSxld88
    http://play.golang.org/p/lEhDXo1b15
    On 13/04/2014, at 1:01 AM, "Andy Balholm" wrote:

    Well, starting with 0 anyway! :-( I should have copied directly from my working code.

    But if you replace that 1 with a 0, the assembly output is actually identical to for i := range s
    On Apr 12, 2014, at 12:44 AM, Dan Kortschak wrote:

    More realistically i, l := 0, len(s); i < l; i++
    On 12/04/2014, at 3:00 PM, "Andy Balholm" wrote:

    I was wrong. It generates exactly the same code as for i := 1; i < len(s); i++.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • William Kennedy at Apr 11, 2014 at 7:29 pm
    Just incase some of you have never seen this before. Check out these links:

    This is Martin Thompson's blog:
    http://mechanical-sympathy.blogspot.com/

    This is a recent podcast on Software Engineering Radio:
    http://www.se-radio.net/2014/02/episode-201-martin-thompson-on-mechanical-sympathy/

    I found it really interesting.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedApr 10, '14 at 5:59a
activeApr 13, '14 at 5:40p
posts15
users7
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase