New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make UUID an array type #3
Comments
Original comment by |
+1 I agree that being able to use UUIDs as map keys would greatly add many algorithms that need to build lookup tables of objects based on ID. |
I would like to see benchmarks using This playground link demonstrates what I mean here: http://play.golang.org/p/nItcogmGee Anyway, I really would be interested in a benchmark if someone wanted to put one together. It's all about quantifying the overhead because, if it is slower, that may just mean the developer has to think about the tradeoff of parsing the strings and if they really need to translate keys back to UUIDs. |
On a 64 bit machine, a string is represented by 2 64 bit values, so 16 bytes, the number of bytes in a UUID. This would be breaking change, however, unless we have a parallel set of functions and make the standard functions simply return slices into the underlying array. A slice actually is 3 values, so 24 bytes on a 64 bit system. I will think about this some more. |
Quite right. My mistake. It does seem like a In terms of maintaining the API maybe the proposal of a method
You could actually define a `type Array [16]byte. Meh. Not sure it's a big deal. |
For proof of concept, I created a new package, called uu whose basic type is "type ID [16]byte". It has nearly the same signatures as the current uuid package, though it returns errors rather than nil for bad UUIDs. It is as fast or faster than the current uuid package with the benchmarks in uuid_test. I then rewrote the existing uuid package to more or less be a wrapper for the array version (for example, all the node and time information is only found in the new uu package). It was pretty close in performance to the existing package. I named the new type ID so packages importing uu would use the type uu.ID vs the existing uuid.UUID. Here are the numbers I got from 5 runs of each, sorted by benchmark and time:
|
The biggest improvement seems to be in Did you know that you can also increase the amount of iterations in a benchmark by setting |
I do wonder if it is a mistake to have type Record struct {
UUID uu.ID
}
r := &Record{}
// ... I think the a nil zero-value for |
After a brief exchange with Russ (rsc) I have renamed uu to be uuid and ID to UUID so it looks like the current package, so github.com/pborman/uuid/uuid is the name of the package. Russ also suggested just changing the API and only having a single library with the new API as people should be using vendoring if they want the old behavior. I think vendoring is still too new and most people are not using it and the new API would absolutely break almost all uses of the package (mostly due to the change in Parse). A slice is a reference (though it cannot be converted back to the underlying array). It does support the concept of a missing UUID and the NIL UUID (Note that a NIL UUID is defined as a UUID with all 0's). Parse in the new package returns a UUID and an error. Here is the implementation of Parse in the wrapped (old) package:
On the negative side, the following code (from json_test.go)
Produces
with the new package and
with the old package. I am not sure which is overall better at the moment. |
I agree that vendoring is probably still too new, if only for the fact that some people think the Go compiler has gotten too slow and are stuck on go1.4 until it improves. Vendoring will always be enabled in go1.6 iirc. I think the biggest problem with the JSON example is that the |
Take a look at https://github.com/pborman/uuid2, it has all the new code. I think for people using JSON, they are better off with the sliced version. Everyone else is probably better off with the array version. |
I would rather there just be one version. But this is your project and I will critique your branch if this is how you would like to proceed.
u := uuid.Must(uuid.NewUUID())
// ...
I don't really notice anything else for now. |
@pborman The json encoding differences could also be "solved" by implementing the json Marshaler Interface. |
@freeformz: In the array case it cannot be solved because there is nothing to differentiate between a bad UUID and the NIL UUID. @bmatsuo: I agree with having just one package, but I feel locked into the current API for the current package name. I did a brief search internally and I would have to fix a lot of code at Google if Parse changed and UUID was no longer a slice. Just adding Array() might end up being the best compromise. |
I threw together some benchmarks of an
edit: The reason there are so many iterations is because I ran the benchmarks with edit 2: The UUID_Array benchmark is higher because it makes an allocation slicing the resulting array to test its value. Strangely, removing the allocation increases the time slightly to ~18ns/op. |
These benchmarks have made me a little concerned that byte-array comparison may not be as optimized as string/[]byte comparison. And that it may indeed not be as great for map keys as one could imagine (it still might be better, IDK). |
I simplified your benchmark to:
The results were:
Which corresponds with what you saw, though not as an extreme difference. I tried running the same test built with gccgo and the results are:
which is exactly the opposite! |
I did a benchmark of inserting 128 random UUIDs into a map (the same 128 for all tests). In one test I use the string form, the other used a 16 byte array. I did not include any time to generate them in the benchmark, just the insertion time. The results were:
So there is a benefit in maps to use arrays. |
Thanks for running these sets of benchmarks. I think they are conclusive as well. Would you like for me to open a PR for the |
Sure, why don't you put one together, along with the String method, of course. Thanks! |
Good call on |
It turns out I was not supposed to migrate from code.google.com to my personal github.com repository, rather, it was supposed to go into github.com/google. This package has been forked into https://github.com/google/uuid. Since the new location is not really in use, it is a perfect time to change the API, including moving to an array type. I have done this. I welcome any comments you might have. Now is the time to change the API if it is going to be changed. If you would like to see changes in the API (nor promises), please add them to this new issue. I am not removing this repository as many people are using it. It also will continue to have the same API. I probably will, at some point, make this version a wrapper around the forked version in Thanks again to everyone who has used and/or contributed to this package. |
Original issue reported on code.google.com by
attilaolah
on 16 Dec 2014 at 2:58The text was updated successfully, but these errors were encountered: