diode library dig:
- Use of sync.Pool (http://vsdmars.blogspot.com/2018/10/golangbook-concurrency-in-go-katherine.html) to reuse object with limited size.
(i.e remember to put the get object back to the pool instead of getting new instance from New func)
https://github.com/rs/zerolog/blob/master/diode/diode.go#L108
Use decorator in a neat way(as closure/lambda calculus):
https://github.com/rs/zerolog/blob/master/diode/internal/diodes/waiter.go#L36
https://github.com/rs/zerolog/blob/master/diode/internal/diodes/poller.go#L26:6 - type contains anonymous interface as carrier to store pointers to concrete type instance makes the type copyable with low cost.
https://github.com/rs/zerolog/blob/master/diode/diode.go#L51
Also, without pointers, less triggering GC to track objects(through layer of layer of pointers) - Use context to clean up resource(in my Actor library or rmqctl tool uses it a lot, a everyone-should-know pattern, aka. Graceful Shutdown)
https://github.com/rs/zerolog/blob/master/diode/internal/diodes/waiter.go#L41 - Two types of writing data to I/O:
- polling (set time interval. polling data to write in every time interval)
- waiting (using conditional variable, once there's a write, fire off conditional variable and do the real I/O operation.)
Use conditional variable, which, does have mutex lock.
https://github.com/rs/zerolog/blob/master/diode/internal/diodes/waiter.go#L33 - Using ring-buffer to store/fetch written data.
Same as Go's go-routine with channel. For any fast retrieving / writing
data needs, since sized ring-buffer can take advantage of CPU cache pre-fetching.
https://github.com/rs/zerolog/blob/master/diode/internal/diodes/many_to_one.go#L41
https://github.com/rs/zerolog/blob/master/diode/internal/diodes/many_to_one.go#L70
The rest of zerolog code is straight forward and clean, lesson learned:
- use sync.Pool to reuse object, should normalize the instance size before putting it back to sync.Pool
- use embedded struct technique to extend interface. (Used in my Actor project)
- use anonymous interface as generic type, cast back to proper interface and make the function call.
- Go, same as C++, C, default copy by value. memcpy is fast, use it as your friend.
e.g
type Run struct{
data *Data
runnerInterface
}
Copy of Run instance is fast with the size of 8 bytes(ptr) + 16 bytes(interface)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.