Skip to content

Provide example of asynchronous and concurrent tasks using unsync #2792

@MarcSkovMadsen

Description

@MarcSkovMadsen

As your experience with Panel grows you start to want to make highly performant Panel apps. There is not so much information on this out there.

Panel provides the guide Async and Concurrency.

An approach that can combine async, threading and multiprocessing seems to be unsync.

It is discussed here https://discourse.holoviz.org/t/async-and-concurrency-for-dummies/2546.

@danmaty and I are discussing if we could provide something useful for Panel like a Gallery Example.

Marc Wishes

  • Can compare example to bare bones example without using async and concurrency. How much does this really improve things.
  • Speed up loading as described here https://discourse.holoviz.org/t/async-and-concurrency-for-dummies/2546/4?u=marc
  • Speeds up
    • data load
    • (pandas) data transformation/ modelling
    • data visualization
  • Updates things in the background. Like for example a clock ...
  • Demonstrates the use of async, threading and multiprocessing and provides guidance on when to use what. Or it is just very clear from our example.
  • Mentioned in Async and Concurrency guide

Example

From https://discourse.holoviz.org/t/async-and-concurrency-for-dummies/2546/9?u=marc

unsync-demo.mp4
import panel as pn
import param
from unsync import unsync
from time import sleep as sl
from time import strftime as st
from panel.layout.gridstack import GridStack

CSS = """
#header {
    background-color: rgba(255,255,255,0.33);
    -ms-box-shadow: none !important;
    -o-box-shadow: none !important;
    -moz-box-shadow: none !important;
    -webkit-box-shadow: none !important;
    box-shadow: none !important;
}

.main-content {
    transition: all 0.2s cubic-bezier(0.945, 0.020, 0.270, 0.665);
    width: 100%;
    height: calc(100vh - 76px);
    padding: 10px;
}

body {
    background: radial-gradient(#B8BEB4, #71685F);
}
 
.bk-root button.button {
    width:65px;
    height:55px;
    position:absolute;
    bottom:0px;
    background-color: rgba(255,255,255,0.33);
    color:#FFF;
    border-radius:25px;
    text-align:center;
    box-shadow: 2px 2px 3px black;
    transition: all 0.2s ease-in-out;
    font-size:30px;
    border-color: rgba(255,255,255,0.33);
}

.bk-root button.button:hover {
    box-shadow: 4px 4px 3px black;
    background-color: rgba(255,255,255,0.33);
    transform: scale(1.05);
    border-color: rgba(255,255,255,0.33);
    cursor: pointer;
}

.bk-root button.button:active {
    transform: translateY(1px);
}
"""

pn.config.sizing_mode = 'stretch_both'
pn.extension('gridstack', raw_css=[CSS])

playSVG="""<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 20 20" height="48px" viewBox="0 0 20 20" width="48px" fill="#000000"><g><rect fill="none" height="20" width="20"/></g><g><g><path d="M10,2c-4.42,0-8,3.58-8,8s3.58,8,8,8s8-3.58,8-8S14.42,2,10,2z M10,16.5c-3.58,0-6.5-2.92-6.5-6.5S6.42,3.5,10,3.5 s6.5,2.92,6.5,6.5S13.58,16.5,10,16.5z"/><polygon points="8,13.5 13.5,10 8,6.5"/></g></g></svg>
"""
pauseSVG="""<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
"""
stopSVG="""<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 0 24 24" width="48px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M16 8v8H8V8h8m2-2H6v12h12V6z"/></svg>
"""

@unsync
def unsync_func1(name):
    global stop_unsync1
    print('unsync1', name)
    if name == 'play':
        stop_unsync1 = False
        while 1:
            if stop_unsync1 == True:
                break
            time_unsync1 = st("%H:%M:%S")
            unsync_out1.object = f"<h1>{time_unsync1}</h1>"
            sl(0.1)
            # print('unsync1 running...')
    elif name == 'pause':
        stop_unsync1 = True
    elif name == 'stop':
        stop_unsync1 = True
        unsync_out1.object = "<h1>00:00:00</h1>"

@unsync
def unsync_func2(name):
    global stop_unsync2
    print('unsync2', name)
    if name == 'play':
        stop_unsync2 = False
        while 1:
            if stop_unsync2 == True:
                break
            time_unsync2 = st("%H:%M:%S")
            unsync_out2.object = f"<h1>{time_unsync2}</h1>"
            sl(0.1)
            # print('unsync2 running...')
    elif name == 'pause':
        stop_unsync2 = True
    elif name == 'stop':
        stop_unsync2 = True
        unsync_out2.object = "<h1>00:00:00</h1>"

@unsync
def unsync_func3(name):
    global stop_unsync3
    print('unsync3', name)
    if name == 'play':
        stop_unsync3 = False
        while 1:
            if stop_unsync3 == True:
                break
            time_unsync3 = st("%H:%M:%S")
            unsync_out3.object = f"<h1>{time_unsync3}</h1>"
            sl(0.1)
            # print('unsync3 running...')
    elif name == 'pause':
        stop_unsync3 = True
    elif name == 'stop':
        stop_unsync3 = True
        unsync_out3.object = "<h1>00:00:00</h1>"

class SVGButton(pn.reactive.ReactiveHTML):
    svg = param.String(doc="The SVG")
    name = param.String(doc='Icon ID')
    func_type = param.String(doc='Type of function')

    _template = """<button class="button" type="button" id="button" onclick="${_do}">{{svg}}</button>"""

    def _do(self, _):
        if self.func_type == 'unsync1':
            unsync_func1(self.name)
        elif self.func_type == 'unsync2':
            unsync_func2(self.name)
        elif self.func_type == 'unsync3':
            unsync_func3(self.name)

play_button_unsync1 = SVGButton(svg=playSVG, name='play', func_type='unsync1', height=60, width=60)
pause_button_unsync1 = SVGButton(svg=pauseSVG, name='pause', func_type='unsync1', height=60, width=60)
stop_button_unsync1 = SVGButton(svg=stopSVG, name='stop', func_type='unsync1', height=60, width=60)
unsync_buttons1 = pn.Row(play_button_unsync1, pause_button_unsync1, stop_button_unsync1)

play_button_unsync2 = SVGButton(svg=playSVG, name='play', func_type='unsync2', height=60, width=60)
pause_button_unsync2 = SVGButton(svg=pauseSVG, name='pause', func_type='unsync2', height=60, width=60)
stop_button_unsync2 = SVGButton(svg=stopSVG, name='stop', func_type='unsync2', height=60, width=60)
unsync_buttons2 = pn.Row(play_button_unsync2, pause_button_unsync2, stop_button_unsync2)

play_button_unsync3 = SVGButton(svg=playSVG, name='play', func_type='unsync3', height=60, width=60)
pause_button_unsync3 = SVGButton(svg=pauseSVG, name='pause', func_type='unsync3', height=60, width=60)
stop_button_unsync3 = SVGButton(svg=stopSVG, name='stop', func_type='unsync3', height=60, width=60)
unsync_buttons3 = pn.Row(play_button_unsync3, pause_button_unsync3, stop_button_unsync3)

unsync_out1 = pn.pane.HTML(object="""<h1>00:00:00</h1>""")
unsync_out2 = pn.pane.HTML(object="""<h1>00:00:00</h1>""")
unsync_out3 = pn.pane.HTML(object="""<h1>00:00:00</h1>""")

card_bg='rgba(255,255,255,0.33)'

gs = GridStack(sizing_mode='stretch_both', ncols=5, nrows=3, height=500, allow_resize=False, allow_drag=False)

gs[0:1, 0:5] = pn.Spacer(margin=5)
gs[1:2, 1:2] = pn.Card(unsync_out1, title='Unsync Function 1', background=card_bg, collapsible=False)
gs[1:2, 2:3] = pn.Card(unsync_out2, title='Unsync Function 2', background=card_bg, collapsible=False)
gs[1:2, 3:4] = pn.Card(unsync_out3, title='Unsync Function 3', background=card_bg, collapsible=False)
gs[2:3, 1:2] = unsync_buttons1
gs[2:3, 2:3] = unsync_buttons2
gs[2:3, 3:4] = unsync_buttons3

mt = pn.template.MaterialTemplate(
    header_background='rgba(255,255,255,0.33)',
    title='Unsync Demo',
    main=[gs],
).servable()

App Ideas

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions