Panel: Memoization and caching?

Created on 22 Mar 2020  路  5Comments  路  Source: holoviz/panel

Panel is a wonderful piece of software, I love it, thanks a lot for making it!

However there is one thing that bugs me out, and it's the lack of caching and memoization. A simple, but I think very common case, is to cache the fetching of an external csv file. So far it seems that everytime a user reloads the page, the whole script is re-executed and the csv file must be redownloaded, which makes the loading quite slow (the user gets a blank page for about a minute, because I聽have multiple such csv files).

I know streamlit has support for this case, and also hvplot through datashader, but it's a quite complicated case and not as streamlined. Also, it doesn't allow as far as I understand to serve multiple different users with the same cache constructed by the first user, which would be ideal in terms of loading time.

Is there a caching and if possible memoization feature, maybe undocumented, in Panel? If not, is such a feature planned, or is there a known easy workaround (eg, by using another module)?

Thanks a lot in advance,
Best regards,
Stephen

discussion enhancement

Most helpful comment

The initial plans for param.depends and pn.depends based APIs was always that we would eventually add a memoization decorator so this is most certainly in scope. That being said you make a good point that in many cases it would be desirable to memoize across user sessions. In the moment this can be achieved by manually reading and writing to pn.state.cache but if we want to provide some inbuilt form of memoization we will have to tinker a bit because at least with panel serve the script (or notebook) you are serving is re-executed for each user and simple memoization will therefore not work. I definitely think this is a very important feature though and I'd also like to write a whole user guide about performance tips once this is in place.

All 5 comments

The initial plans for param.depends and pn.depends based APIs was always that we would eventually add a memoization decorator so this is most certainly in scope. That being said you make a good point that in many cases it would be desirable to memoize across user sessions. In the moment this can be achieved by manually reading and writing to pn.state.cache but if we want to provide some inbuilt form of memoization we will have to tinker a bit because at least with panel serve the script (or notebook) you are serving is re-executed for each user and simple memoization will therefore not work. I definitely think this is a very important feature though and I'd also like to write a whole user guide about performance tips once this is in place.

@philippjfr Thank you very much for your fast reply! Those plans sound great, I would love to see Panel support caching and memoization!

Meanwhile, I tried to workaround by using cachier or joblib's Memory, and although both work correctly to reuse the cache between Jupyter Notebook runs (after restarting the kernel), they don't with Panel launched with a Bokeh server, as each cache gets a unique handler instead of reusing the same one (eg: bk_script_1489.my_function() where bk_script_1489. is the part added by Bokeh).

Do you have any idea how I may work around this (forcing all caching requests to use the same cache without bokeh's unique id prepending) by any chance?

Update: if anyone needs a workaround in the meantime, I聽have found that simple_cache and cache (but the latter does not have a licence) work well with pandas dataframes and Panel/Bokeh standalone server. I implemented my solution with simple_cache, and it works well to reuse the same cache across Boker server sessions/users (so different users will reuse the same cache, that's nice!).

Yes! A pattern which automatically caches the source data frame caching would really help. For now was able to achieve this manually using pn.state.cache.

class MyExplorer(param.Parameterized):

    def __init__(self, **kwargs):
        self.df = pn.state.cache["data"] if "data" in pn.state.cache else load_input()
        pn.state.cache["data"] = self.df

    @param.depends("...")
    def make_view():
        plot_df = transform(self.df)
        return hv.Curve...

explorer = MyExplorer(name="")
dashboard = pn.Column(explorer.param, explorer.make_view)

Oh thank you for the example, very helpful! I think yiur cide snippet can be easily converted to a simple caching function decorator, that would be better than my current solution because then no other dependency would be needed :-)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ericmjl picture ericmjl  路  6Comments

maximlt picture maximlt  路  5Comments

MarcSkovMadsen picture MarcSkovMadsen  路  3Comments

kcpevey picture kcpevey  路  4Comments

henriqueribeiro picture henriqueribeiro  路  3Comments