[Python-ideas] async: switch_to_loop and loop_affinity

Jonathan Slenders jonathan at slenders.be
Wed Feb 12 10:33:32 CET 2014


Do you know about run_in_executor?

http://docs.python.org/3.4/library/asyncio-eventloop.html#asyncio.BaseEventLoop.run_in_executor


2014-02-12 10:24 GMT+01:00 David Foster <davidfstr at gmail.com>:

> There has been much talk of the use of async libraries (such as Tulip)
> within the general programming community to avoid the "christmas tree"
> pattern of code indentation in code that uses a lot of callbacks. For
> example, consider the following callback-based code:
>
> def duplicate_file_async(filepath, done):
>     def exists_async(does_exist):
>         if not does_exist:
>             done(False)
>             return
>         def entire_file_read(contents):
>             if not contents:
>                 done(False)
>                 return
>             def file_written(success):
>                 done(success)
>             write_entire_file_async(filepath + ' copy', contents,
> file_written)
>         read_entire_file_async(filepath, entire_file_read)
>     exists_async(filepath)
>
> This code be rewritten in Tulip as:
>
> @async.coroutine
> def duplicate_file_async(filepath):
>     if not yield from exists_async(filepath):
>         return False
>     contents = yield from read_entire_file_async(filepath)
>     if not contents:
>         return False
>     return yield from write_entire_file_async(filepath + ' copy',
> contents)
>
> Much more clear, no?
>
> Tulip, however, does not appear to address a slightly different problem I
> run into where I need different parts of the same conceptual function to
> run on specific *different* threads. 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)
>
>         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 = ...
>
> @async.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)
>
> Or even better: If you created a decorators like @loop_affinity(*_loop)
> that automatically called switch_to_loop(...) if the current event loop
> wasn't correct, you could even write the following even-more simplified
> version:
>
> @async.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)
>
> @async.loop_affinity(db_loop)
> def fetch_node_from_db(...): ...
>
> @async.loop_affinity(bg_loop)
> def fetch_node_from_internet(...): ...
>
> @async.loop_affinity(db_loop)
> def insert_into_db(...): ...
>
> @async.loop_affinity(ui_loop)
> def set_contents(...): ...
>
> Wouldn't that be just grand? I have prototyped switch_to_loop(...)
> successfully in Tulip, albeit with a race condition I was unable to isolate.
>
> How about some equivalent to switch_to_loop(...) and loop_affinity(...) in
> a future version of Tulip?
>
> --
> David Foster
> http://dafoster.net/
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20140212/445a70b9/attachment-0001.html>


More information about the Python-ideas mailing list