*(Migrating this thread from the python-ideas list)*

Tulip does not appear to address a scenario of mine where I need different 
parts of the same coroutine to run on specific threads or event loops. 
Consider the following code which needs different parts executed on a UI 
thread, database thread, and background thread:

def tree_node_clicked(tree_node):
    print('Clicked: ' + repr(tree_node))
    def db_task():
        db_node = fetch_node_from_db(tree_node.url)

        def process_node(db_node):
            tree_node.set_contents(db_node.contents)
            # (done)

        if db_node is not None:
            def bg_task():
                db_node = fetch_node_from_internet(tree_node.url)
                def db_task():
                    insert_into_db(db_node)
                    ui_call_soon(process_node, db_node)
                db_call_soon(db_task)
            bg_call_soon(bg_task)
        else:
            ui_call_soon(process_node, db_node)
    db_call_soon(db_task)

Imagine if you could write this function like the following:

ui_loop = ...
db_loop = ...
bg_loop = ...

@asyncio.coroutine
def tree_node_clicked(tree_node):
    print('Clicked: ' + repr(tree_node))

    yield from switch_to_loop(db_loop)
    db_node = fetch_node_from_db(tree_node)
    if db_node is not None:
        yield from switch_to_loop(bg_loop)
        db_node = fetch_node_from_internet(tree_node.url)

        yield from switch_to_loop(db_loop)
        insert_into_db(db_node)

    yield from switch_to_loop(ui_loop)
    tree_node.set_contents(db_node.contents)

(The preceding relies on a hypothetical *switch_to_loop* primitive.)

Or even better: If you created a decorator like *@loop_affinity* that 
automatically called switch_to_loop(...) if the current event loop wasn't 
correct, you could even write the following even-more simplified version:

@asyncio.coroutine
def tree_node_clicked(tree_node):
    print('Clicked: ' + repr(tree_node))
    db_node = yield from fetch_node_from_db(tree_node)
    if db_node is not None:
        db_node = yield from fetch_node_from_internet(tree_node.url)
        yield from insert_into_db(db_node)
    yield from tree_node.set_contents(db_node.contents)

@loop_affinity(db_loop)
def fetch_node_from_db(...): ...

@loop_affinity(bg_loop)
def fetch_node_from_internet(...): ...

@loop_affinity(db_loop)
def insert_into_db(...): ...

@loop_affinity(ui_loop)
def set_contents(...): ...

Wouldn't that be just grand?

Is there a way to implement a primitive similar to switch_to_loop(...) on 
top of existing primitives in Tulip? Or would that be considered a new 
feature?

Jonathan Slenders and Guido suggested on python-ideas that I would be able 
to implement this idea (although perhaps not switch_to_loop) using 
run_in_executor. Regarding specifically the implementation 
of switch_to_loop, it is not clear to me how I could get access to the next 
part of the current coroutine which I would need to pass to run_in_executor 
(or something similar).

Reply via email to