I am working with large database that takes 5-6 seconds to call, so I get the whole database at once during class instantiation (on a server side).
I also have two @anvil.server.call methods and each needs access to the object.
I don’t want to create two instances, it will take double time so I tried making the class singleton. That didn’t work.
Any advice how to do this with only one instantiation?
(used singleton example from here: https://www.tutorialspoint.com/python_design_patterns/python_design_patterns_singleton.htm)
class Everything(object):
__instance = None
@staticmethod
def getInstance():
""" Static access method. """
if Everything.__instance == None:
Everything()
return Everything.__instance
def __init__(self):
""" Virtually private constructor. """
if Everything.__instance != None:
raise Exception("This class is a singleton!")
else:
Everything.__instance = self
db = self.get_database()
def get_database(self):
print('Loading time consuming info …')
@anvil.server.callable
def get_employee_groups():
everything = Everything.getInstance()
print(everything)
@anvil.server.callable
def get_fig_list_dict():
everything = Everything.getInstance()
print(everything)
Loading time consuming info …
<BLIDashboard.ServerModule.Everything object at 0x7fa28416f5d0>
Loading time consuming info …
<BLIDashboard.ServerModule.Everything object at 0x7f07a7c1e390>
The two address are different. Any help is welcome.
I think the problem you’re facing is related to this from the docs:
Persistent Server Modules
Each server function call is executed in a new Python interpreter, meaning that global variables won’t persist between server function calls.
Enabling Persistent Server Modules by checking ‘Keep server running’ allows the same interpreter to be used for multiple server function calls.
Persistent Server Modules are available on the Business Plan and above.
Do you send db to the client in some form?
client global variables might be the way to go…
App Structure:
- module: _globals
- form: Form1
- form: Form2
_globals
fig_list = None
employee_groups = None
Form1
from . import _globals
class Form1(Form1Template):
def __init__(self, **properties):
if _globals.employee_groups is None:
_globals.employee_groups, _globals.fig_list = anvil.server.call('get_groups_and_figs')
self.employee_groups = _globals.employee_groups
Form2
from . import _globals
class Form2(Form2Template):
def __init__(self, **properties):
if _globals.fig_list is None:
_globals.employee_groups, _globals.fig_list = anvil.server.call('get_groups_and_figs')
self.fig_list = _globals.fig_list
1 Like
The singleton described on that tutorial applies to Python scripts running on one computer. An Anvil app runs on two computers, the server and the client.
The client session starts when you start the app and ends when you leave it, so you can use client side globals as described by @stucork.
A new server side session starts every time the server is contacted, so globals will not survive between calls. You can try with the “keep server running” option, and if you are lucky your globals will be shared across all calls from all client requests of all users. But the server could shut down whenever it likes or could pass the control to another server when it feels tired.
I often can speed up the loading of table rows by polishing the queries, reorganizing data in fewer rows with Simple Object columns (faster than linking tables with many rows) and/or using SQL queries instead of Anvil app_table interface.
2 Likes
Thanks sc549, these are good tips.
I generally convert database data to pandas dataframes, but since I don’t have pandas in a client I tend to pass only final result. I could try to prep the data in a different form.
1 Like
Thanks Stefano,
I had no idea about Simple Objects, I could definitely use those in the future.
You can also cache information on the client side in a client module. That might work if you have some mechanism for knowing when a client needs to update the cached info.