Comments (4)
Here's an example of what I mean. Let's say I have a cache and some kind of database, both stored in global variables. I want to load and cache the result of a database query whenever there's a cache miss. Using Fetch
as it is now, I would do something like this:
func getCachedValueOrLoadValue(key string) (interface{}, error) {
return myCache.Fetch(key, cacheTTL, func() (interface{}, error) {
return myDatabase.Query(buildQueryForKey(key))
}
}
That looks straightforward, but what happens internally is more like this (not exactly, but close enough):
type queryClosureParams struct {
key string
}
func newQueryClosureParams(key string) *queryClosureParams {
return &queryClosureParams{key}
}
func queryClosure(params *queryClosureParams) {
return myDatabase.Query(buildQueryForKey(params.key))
}
func getCachedValueOrLoadValue(key string) (interface{}, error) {
params := newQueryClosureParams(key)
return myCache.Fetch(key, cacheTTL, func() (interface{}, error) {
return queryClosure(params)
}
}
What would avoid this is if there were an alternate Fetch
(better name TBD, let's call it Fetch2
for now) that worked like so:
func loadValue(key string) (interface{}, error) {
return myDatabase.Query(buildQueryForKey(key))
}
func getCachedValueOrLoadValue(key string) (interface{}, error) {
return myCache.Fetch2(key, cacheTTL, loadValue)
}
There it doesn't have to create a closure— the function reference is just a simple function value, with no other state.
(This can be a bit tricky to get right because, if loadValue
were a method of some component (like, func (c *MyComponent) loadValue(key string) (interface{}, error)
, it would still behave like a closure because the value of c
is an implicit parameter. The workaround for that is that the MyComponent
type would declare a field like loadValueFn func(string) (interface{}, error)
and then its constructor would do c.loadValueFn := c.loadValue
, which would create a closure that represents the instance method as a simple function— but it would only create it once, not once per query. Again, this is the kind of stuff that won't matter to many people but, since Go is a popular solution for high-traffic services, it makes sense to allow people to leverage Go's flexibility for best performance if they want to.)
from ccache.
Sorry to repeat my last answer, but I think having your own app-specific fetch
makes sense. I think they're both good features, but the permutations of features people might want with fetch makes it hard to manage.
I think adding a section in the readme about 'custom fetches' might be useful.
Thoughts?
from ccache.
Well, I wasn't thinking about this just as an extra feature specific to Fetch, but also a basic design principle that I'd prefer for things to follow in the future even if the API of the existing things can't be changed now. In general, using a stateless function is preferable over using a stateful function (in regard to the state of an individual operation, that is; there might of course be some implicit state in the form of a database connection or whatever)— the latter will usually have some kind of disadvantage on any platform in either efficiency or other areas, I just mentioned the ones it happens to have in Go.
If you want to add some further docs about alternatives to Fetch, that's fine, although I would suggest putting that content in the doc comment for Fetch (at least, to clarify that it's not doing anything you can't already do via other public APIs) rather than in the readme.
from ccache.
Heh— I just realized that in my particular use case, where I'm also using singleflight
, there's no way to completely get rid of this issue because singleflight.Group.Do
also takes a nullary function. Ah well.
from ccache.
Related Issues (20)
- Fetch() is not atomic HOT 2
- ability to set an item that never expires HOT 2
- Stop can cause race detector errors in testing HOT 14
- Bug report: item leak when c.promotables is busy HOT 1
- Bug report: TrackingGet goroutine unsafe with onDelete func HOT 1
- How to get the max performance? HOT 3
- Not Promote on Get HOT 2
- How to promote directly saved item? HOT 1
- OnDelete not called in LayeredCache.gc
- High lock contention in LayeredCache.set with few primary keys HOT 1
- memory leak HOT 3
- New release implemented via generics? HOT 1
- Bug Report: v3.0.0 gc may failed HOT 5
- Bug Report: v3.0.1 gc may failed
- When max size is 3, set() not delete superfluous data HOT 4
- Memory leak during cleanup
- Generic key type HOT 2
- ttl not working HOT 4
- Fix flaky test HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ccache.