Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #63967

Re: Trying to wrap my head around futures and coroutines

Path csiph.com!usenet.pasdenom.info!dedibox.gegeweb.org!gegeweb.eu!nntpfeed.proxad.net!proxad.net!feeder1-2.proxad.net!usenet-fr.net!nerim.net!novso.com!newsfeed.xs4all.nl!newsfeed2.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail
Return-Path <pconnell@gmail.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.028
X-Spam-Evidence '*H*': 0.94; '*S*': 0.00; 'buttons': 0.09; 'executes': 0.09; 'linear': 0.09; 'cc:addr:python-list': 0.11; 'def': 0.12; 'gui': 0.12; 'jan': 0.12; '(apologies': 0.16; 'canceled': 0.16; 'coroutines': 0.16; 'corresponds': 0.16; 'hypothetical': 0.16; 'main():': 0.16; 'perceived': 0.16; 's/he': 0.16; 'true:': 0.16; 'wrote:': 0.18; 'code.': 0.18; 'bit': 0.19; 'seems': 0.21; '(the': 0.22; 'cc:addr:python.org': 0.22; 'header :User-Agent:1': 0.23; 'instead.': 0.24; 'skip': 0.24; 'decide': 0.24; 'mon,': 0.24; 'together.': 0.24; 'cheers,': 0.24; 'looks': 0.24; 'cc:2**0': 0.24; 'sort': 0.25; 'task': 0.26; 'header:In- Reply-To:1': 0.27; 'point': 0.28; "i'm": 0.30; 'work.': 0.31; 'code': 0.31; '"do': 0.31; 'complete,': 0.31; 'run': 0.32; 'another': 0.32; 'running': 0.33; 'trouble': 0.34; 'something': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'cancel': 0.36; 'executing': 0.36; 'vice': 0.36; 'yield': 0.36; 'charset:us- ascii': 0.36; 'so,': 0.37; 'two': 0.37; 'being': 0.38; 'gmail': 0.38; 'little': 0.38; 'structure': 0.39; 'how': 0.40; 'chain': 0.60; 'event.': 0.60; 'new': 0.61; 'name:': 0.61; 'received:173': 0.61; 'simple': 0.61; 'content-disposition:inline': 0.62; 'complete': 0.62; 'name': 0.63; 'real': 0.63; 'to:addr:gmail.com': 0.65; 'roles': 0.68; 'started.': 0.68; 'facilities': 0.69; 'user,': 0.69; 'safe': 0.72; 'guaranteed': 0.75; 'code):': 0.84; 'phil': 0.84; 'activity,': 0.91
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:in-reply-to:user-agent; bh=gera2EnrgdEWo0kLocGbdmVWUe2H0VNLE+a8NEb1m4s=; b=KcbU1dmP+P7N+8GeAUYNxY3HGkScNkc+lWL9OAxkBnVCUa32tl8kIz+eA5rL7DztNl qSgv1f5+DbOAOY/yQQU+jq0OmemxCXkCqf1xEbqpEcFZn7hhVLqy/wy731nVtDCU+mmk gpqHmqhBwY0XvE7QpyXSNLNvu5IPFkpdnD5ALre4+jIjBj0T4e1sPkyWPPvrL5kVcAbf t9+fbXihiAA1/c17dYUZIEfhT3FQSJSZ02yRQIm86DqNm836PmGUnrZaQ0NDZuCOtUOe 9K4CfnUK8u2lX8AKMVfVobsSSsc7Zgoed+yIqFoRftRl6wfuS98+3U7dUHqu9GR21MdA wE8w==
X-Received by 10.14.102.67 with SMTP id c43mr95130eeg.23.1389781116130; Wed, 15 Jan 2014 02:18:36 -0800 (PST)
Date Wed, 15 Jan 2014 10:18:32 +0000
From Phil Connell <pconnell@gmail.com>
To Skip Montanaro <skip.montanaro@gmail.com>
Subject Re: Trying to wrap my head around futures and coroutines
References <CANc-5UzZj9vNdZVvDNosaGaOLXhOykagF_HkqafYjnoNguD2Mw@mail.gmail.com> <CANc-5UxzRtBura1ve9tQ5o=RQCasm_VpxewerGLq1_8B0LMpjQ@mail.gmail.com>
MIME-Version 1.0
Content-Type text/plain; charset=us-ascii
Content-Disposition inline
In-Reply-To <CANc-5UxzRtBura1ve9tQ5o=RQCasm_VpxewerGLq1_8B0LMpjQ@mail.gmail.com>
User-Agent Mutt/1.5.22 (2013-10-16)
Cc Python <python-list@python.org>
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <https://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <https://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.5498.1389781124.18130.python-list@python.org> (permalink)
Lines 95
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1389781124 news.xs4all.nl 2846 [2001:888:2000:d::a6]:46202
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:63967

Show key headers only | View raw


On Mon, Jan 06, 2014 at 06:56:00PM -0600, Skip Montanaro wrote:
> So, I'm looking for a little guidance. It seems to me that futures,
> coroutines, and/or the new Tulip/asyncio package might be my salvation, but
> I'm having a bit of trouble seeing exactly how that would work. Let me
> outline a simple hypothetical calculation. I'm looking for ways in which
> these new facilities might improve the structure of my code.

This instinct is exactly right -- the point of coroutines and tulip futures is
to liberate you from having to daisy chain callbacks together.


> 
> Let's say I have a dead simple GUI with two buttons labeled, "Do A" and "Do
> B". Each corresponds to executing a particular activity, A or B, which take
> some non-zero amount of time to complete (as perceived by the user) or
> cancel (as perceived by the state of the running system - not safe to run A
> until B is complete/canceled, and vice versa). The user, being the fickle
> sort that he is, might change his mind while A is running, and decide to
> execute B instead. (The roles can also be reversed.) If s/he wants to run
> task A, task B must be canceled or allowed to complete before A can be
> started. Logically, the code looks something like (I fear Gmail is going to
> destroy my indentation):
> 
> def do_A():
> when B is complete, _do_A()
> cancel_B()
> 
> def do_B():
> when A is complete, _do_B()
> cancel_A()
> 
> def _do_A():
> do the real A work here, we are guaranteed B is no longer running
> 
> def _do_B():
> do the real B work here, we are guaranteed A is no longer running
> 
> cancel_A and cancel_B might be no-ops, in which case they need to start up
> the other calculation immediately, if one is pending.

It strikes me that what you have two linear sequences of 'things to do':
    - 'Tasks', started in reaction to some event.
    - Cancellations, if a particular task happens to be running.

So, a reasonable design is to have two long-running coroutines, one that
executes your 'tasks' sequentially, and another that executes cancellations.
These are both fed 'things to do' via a couple of queues populated in event
callbacks.

Something like (apologies for typos/non-working code):


cancel_queue = asyncio.Queue()
run_queue = asyncio.Queue()

running_task = None
running_task_name = ""

def do_A():
    cancel_queue.put_nowait("B")
    run_queue.put_nowait(("A", _do_A()))

def do_B():
    cancel_queue.put_nowait("A")
    run_queue.put_nowait(("B", _do_B()))

def do_C():
    run_queue.put_nowait(("C", _do_C()))

@asyncio.coroutine
def canceller():
    while True:
        name = yield from cancel_queue.get()
        if running_task_name == name:
            running_task.cancel()

@asyncio.coroutine
def runner():
    while True:
        name, coro = yield from run_queue.get()
        running_task_name = name
        running_task = asyncio.async(coro)
        yield from running_task

def main():
    ...
    cancel_task = asyncio.Task(canceller())
    run_task = asyncio.Task(runner())
    ...



Cheers,
Phil

Back to comp.lang.python | Previous | Next | Find similar | Unroll thread


Thread

Re: Trying to wrap my head around futures and coroutines Phil Connell <pconnell@gmail.com> - 2014-01-15 10:18 +0000

csiph-web