holoviz / holoviews

With Holoviews, your data visualizes itself.
https://holoviews.org
BSD 3-Clause "New" or "Revised" License
2.69k stars 402 forks source link

Make holoviews threadsafe #6162

Open douglas-raillard-arm opened 6 months ago

douglas-raillard-arm commented 6 months ago

Is your feature request related to a problem? Please describe.

I'm trying to build a bunch of plots rendered HTML/JS as quickly as possible as part of building a Sphinx documentation.

Describe the solution you'd like

Be able to call e.g. hv.Curve() and do the bokeh rendering in a concurrent.futures.ThreadPoolExecutor

Describe alternatives you've considered

Serial execution is possible, just slower

Additional context

Trying it seemed to work, until it failed (randomly it seems):

  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/lisa/analysis/base.py", line 693, in set_options
    return fig.options(
           ^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/core/dimension.py", line 1276, in options
    obj = obj.opts._dispatch_opts(expanded, backend=backend, clone=clone)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/core/accessors.py", line 583, in _dispatch_opts
    return self._base_opts(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/core/accessors.py", line 658, in _base_opts
    return opts.apply_groups(self._obj, **dict(kwargs, **new_kwargs))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/util/__init__.py", line 245, in apply_groups
    obj = cls._apply_groups_to_backend(obj, backend_opts, backend_loop, clone)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/util/__init__.py", line 171, in _apply_groups_to_backend
    return StoreOptions.set_options(obj_handle, options, backend=backend)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/core/options.py", line 1877, in set_options
    applied = cls.propagate_ids(
              ^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/core/options.py", line 1530, in propagate_ids
    raise AssertionError("New option id %d does not match any "
AssertionError: New option id 126179 does not match any option trees in Store.custom_options.
Exception occurred:
  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/.lisa-venv-3.11/lib/python3.11/site-packages/holoviews/core/options.py", line 1530, in propagate_ids
    raise AssertionError("New option id %d does not match any "
AssertionError: New option id 126179 does not match any option trees in Store.custom_options.
The full traceback has been saved in /tmp/sphinx-err-m1x1j683.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
MarcSkovMadsen commented 6 months ago

If possible please provide a minimum, reproducible example. Thx.

douglas-raillard-arm commented 6 months ago

I unfortunately have no reproducible example, let alone minimal. It was working "perfectly well" locally and only tripped with the backtrace in our CI when building the Sphinx documentation for our project. AFAICT that is probably due to timings on the CI being different than locally and not even necessarily fully reproducible there either. The fig variable in that call: https://gitlab.arm.com/tooling/lisa/-/blob/main/lisa/analysis/base.py?ref_type=heads#L693

  File "/home/ubuntu/builds/XNd7eey6/1/tooling/lisa/lisa/analysis/base.py", line 693, in set_options
    return fig.options(

is an object like hv.Curve(). The function dispatched on the concurrent.futures.ThreadPoolExecutor is creating such objects, then renders it to HTML+JS (using bokeh), and the value returned by the worker function is a big string ready to be appended in a docstring for Sphinx to render: https://tooling.sites.arm.com/lisa/latest/trace_analysis.html#lisa.analysis.frequency.FrequencyAnalysis.plot_cpu_frequencies