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


Groups > comp.lang.python > #86138 > unrolled thread

Question on asyncio

Started bypfranken85@gmail.com
First post2015-02-22 09:47 -0800
Last post2015-02-23 18:30 +0200
Articles 6 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  Question on asyncio pfranken85@gmail.com - 2015-02-22 09:47 -0800
    Re: Question on asyncio Marko Rauhamaa <marko@pacujo.net> - 2015-02-22 23:21 +0200
      Re: Question on asyncio pfranken85@gmail.com - 2015-02-23 01:48 -0800
        Re: Question on asyncio Marko Rauhamaa <marko@pacujo.net> - 2015-02-23 15:27 +0200
          Re: Question on asyncio Jonas Wielicki <jonas@wielicki.name> - 2015-02-23 16:05 +0100
            Re: Question on asyncio Marko Rauhamaa <marko@pacujo.net> - 2015-02-23 18:30 +0200

#86138 — Question on asyncio

Frompfranken85@gmail.com
Date2015-02-22 09:47 -0800
SubjectQuestion on asyncio
Message-ID<52b94569-1480-4a05-a58f-13c2cb19229a@googlegroups.com>
Hello!

I am just trying to get familiar with asyncio. It seems to be a good thing, however, I am still having troubles and feel pretty puzzled although I think I got the point what async IO means. This is the problem I am trying to accomplish:

I have some functions which are reading values from hardware. If one of the values changes, I want a corresponding notification to the connected clients. The network part shouldn't be the problem. Here is what I got so far:

@asyncio.coroutine
def check():
  old_val = read_value_from_device()
  yield from asyncio.sleep(2)
  new_val = read_value_from_device()
  # we may have fluctuations, so we introduce a threshold
  if abs(new_val-old_val) > 0.05:
      return new_val
  else:
      return None
      
@asyncio.coroutine
def runner():
  while 1:
    new = yield from check()
    print(new)
      
loop = asyncio.get_event_loop()
loop.run_until_complete(update())


Is this the way one would accomplish this task? Or are there better ways? Should read_value_from_device() be a @coroutine as well? It may contain parts that take a while ... Of course, instead of print(new) I would add the corresponding calls for notifying the client about the update.

Thanks!

[toc] | [next] | [standalone]


#86156

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-02-22 23:21 +0200
Message-ID<8761atiqvt.fsf@elektro.pacujo.net>
In reply to#86138
pfranken85@gmail.com:

> I have some functions which are reading values from hardware. If one
> of the values changes, I want a corresponding notification to the
> connected clients. The network part shouldn't be the problem. Here is
> what I got so far:
>
> @asyncio.coroutine
> def check():
>   old_val = read_value_from_device()
>   yield from asyncio.sleep(2)
>   new_val = read_value_from_device()
>   # we may have fluctuations, so we introduce a threshold
>   if abs(new_val-old_val) > 0.05:
>       return new_val
>   else:
>       return None
>       
> @asyncio.coroutine
> def runner():
>   while 1:
>     new = yield from check()
>     print(new)

In asyncio, you typically ignore the value returned by yield. While
generators use yield to communicate results to the calling program,
coroutines use yield only as a "trick" to implement cooperative
multitasking and an illusion of multithreading.

Thus, "yield from" in asyncio should be read, "this is a blocking
state."

> Is this the way one would accomplish this task? Or are there better
> ways? Should read_value_from_device() be a @coroutine as well? It may
> contain parts that take a while ... Of course, instead of print(new) I
> would add the corresponding calls for notifying the client about the
> update.

How do you read a value from the hardware? Do you use a C extension? Do
you want read_value_from_device() to block until the hardware has the
value available or is the value always available for instantaneous
reading?

If the value is available instantaneously, you don't need to turn it
into a coroutine. However, if blocking is involved, you definitely
should do that. Depending on your hardware API it can be easy or
difficult. If you are running CPython over linux, hardware access
probably is abstracted over a file descriptor and a coroutine interface
would be simple.


Marko

[toc] | [prev] | [next] | [standalone]


#86204

Frompfranken85@gmail.com
Date2015-02-23 01:48 -0800
Message-ID<5c9fa6a5-f92a-42a8-a760-9477f9d8d0d2@googlegroups.com>
In reply to#86156
Hello Marko!

Am Sonntag, 22. Februar 2015 22:21:55 UTC+1 schrieb Marko Rauhamaa:
> In asyncio, you typically ignore the value returned by yield. While
> generators use yield to communicate results to the calling program,
> coroutines use yield only as a "trick" to implement cooperative
> multitasking and an illusion of multithreading.

Really? I saw several exmaples, where a coroutine returned a value which was then picked up from the yield from statement...

> 
> Thus, "yield from" in asyncio should be read, "this is a blocking
> state."
> 
> > Is this the way one would accomplish this task? Or are there better
> > ways? Should read_value_from_device() be a @coroutine as well? It may
> > contain parts that take a while ... Of course, instead of print(new) I
> > would add the corresponding calls for notifying the client about the
> > update.
> 
> How do you read a value from the hardware? Do you use a C extension? Do
> you want read_value_from_device() to block until the hardware has the
> value available or is the value always available for instantaneous
> reading?
> 
> If the value is available instantaneously, you don't need to turn it
> into a coroutine. However, if blocking is involved, you definitely
> should do that. Depending on your hardware API it can be easy or
> difficult. If you are running CPython over linux, hardware access
> probably is abstracted over a file descriptor and a coroutine interface
> would be simple.


The corresponding call is a call to the python smbus library. It includes several sleeps (even though they are only about 50ms). Therefore I think it is worthwhile to encapsulate it into a coroutine. However I am not quite sure, how I should call it and integrate it into the main loop. In particular, do I need something like the runner routine() with and infinite while loop or can just add the check() routine to the main loop, so that it gets executed regularly and call the corresponding notifier whenever the condition of the if statement is true?

Thanks for your input!

[toc] | [prev] | [next] | [standalone]


#86216

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-02-23 15:27 +0200
Message-ID<87k2z8dagc.fsf@elektro.pacujo.net>
In reply to#86204
pfranken85@gmail.com:

> Hello Marko!
>
> Am Sonntag, 22. Februar 2015 22:21:55 UTC+1 schrieb Marko Rauhamaa:
>> In asyncio, you typically ignore the value returned by yield. While
>> generators use yield to communicate results to the calling program,
>> coroutines use yield only as a "trick" to implement cooperative
>> multitasking and an illusion of multithreading.
>
> Really? I saw several exmaples, where a coroutine returned a value
> which was then picked up from the yield from statement...

Actually, you might have better information in that regard than me. In
my trials, I never used it like that.

> The corresponding call is a call to the python smbus library. It
> includes several sleeps (even though they are only about 50ms).
> Therefore I think it is worthwhile to encapsulate it into a coroutine.

Maybe. Then you'll probably have to rewrite smbus to work asyncio style.
Those sleeps would then be done as "yield from" statements.


Marko

[toc] | [prev] | [next] | [standalone]


#86226

FromJonas Wielicki <jonas@wielicki.name>
Date2015-02-23 16:05 +0100
Message-ID<mailman.19074.1424703937.18130.python-list@python.org>
In reply to#86216

[Multipart message — attachments visible in raw view] — view raw

On 23.02.2015 14:27, Marko Rauhamaa wrote:
> pfranken85@gmail.com:
>> The corresponding call is a call to the python smbus library. It
>> includes several sleeps (even though they are only about 50ms).
>> Therefore I think it is worthwhile to encapsulate it into a coroutine.
> 
> Maybe. Then you'll probably have to rewrite smbus to work asyncio style.
> Those sleeps would then be done as "yield from" statements.
> 

The manual has a word on this [1]. So I would suggest to use
run_in_executor() instead of trashing and rewriting the whole smbus library.

regards,
jwi

   [1]:
https://docs.python.org/3/library/asyncio-dev.html#handle-blocking-functions-correctly
   [2]:
https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.BaseEventLoop.run_in_executor

[toc] | [prev] | [next] | [standalone]


#86238

FromMarko Rauhamaa <marko@pacujo.net>
Date2015-02-23 18:30 +0200
Message-ID<87a904d1za.fsf@elektro.pacujo.net>
In reply to#86226
Jonas Wielicki <jonas@wielicki.name>:

> On 23.02.2015 14:27, Marko Rauhamaa wrote:
>> pfranken85@gmail.com:
>>> The corresponding call is a call to the python smbus library. It
>>> includes several sleeps (even though they are only about 50ms).
>>> Therefore I think it is worthwhile to encapsulate it into a coroutine.
>> 
>> Maybe. Then you'll probably have to rewrite smbus to work asyncio style.
>> Those sleeps would then be done as "yield from" statements.
>> 
>
> The manual has a word on this [1]. So I would suggest to use
> run_in_executor() instead of trashing and rewriting the whole smbus
> library.

Ok, that's always a fallback. I usually isolate such obnoxious function
calls in a process pool.

But that wouldn't be purely asyncio anymore.

One of the main offenders is the database libraries. They should
definitely provide nonblocking access.


Marko

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web