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: 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 To: Skip Montanaro Subject: Re: Trying to wrap my head around futures and coroutines References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.22 (2013-10-16) Cc: Python X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: 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 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