Asyncio problem, looking for advice.

Akira Li 4kir4.1i at gmail.com
Fri Nov 28 16:04:56 EST 2014


Benjamin Risher <brisher777 at gmail.com> writes:

> On Friday, November 28, 2014 6:12:20 AM UTC-6, Akira Li wrote:
>> Benjamin Risher writes:
>> 
>> > Hello all,
>> >
>> > I'm working on a project to learn asyncio and network programming.
>> > What I'm trying to do is forward a connection from myself to
>> > another machine.  Kind of like an asynchronous python
>> > implementation of fpipe.
>> >
>> > In a nutshell:
>> >
>> > 1 --> start a server listening on localhost
>> > 2 --> connect to server
>> > 3 --> server connects to a listening service (ssh for instance)
>> > 4 --> server handles both connections to pass traffic back and forth through each
>> >
>> > What I have now *kind of* works.  It sends data back and forth,
>> > but when I ssh to localhost -p 12345, i never get the password
>> > prompt.  It looks like one packet hangs out and doesn't get sent
>> > from what I saw in tcpdump.
>> >
>> > Any help would be greatly appreciated.
>> 
>> Do you want to emulate `ssh -L 12345:localhost:22 <host>`?
>> 
>> > Here's a link to the same code as below, just with syntax highlighting etc...
>> > http://pastebin.com/iLE4GZH3
>> 
>> There are several issue e.g., unnecessary async(), deprecated Task()
>> calls but the main issue is that _handle_client() doesn't read
>> concurrently from the server while client writes to it.
>> 
>> You could use asyncio.wait() to run several tasks in parallel
>
>> [1]
>> https://docs.python.org/3/library/asyncio-task.html#example-parallel-execution-of-tasks
>> 
>> [2] http://pastebin.com/g08YaJyz
>> 


> Akira, 
>
> First, thank you very much for your response.  It helps tremendously.
> I have a question or two though, if you don't mind.
>
> You said Task() is deprecated, but it's not listed as such in the
> docs.  Is it just that it's preferred to use other methods instead of
> using Task() directly, or am I missing something?

asyncio is a provisional API [3], it may change without notice (though
it shouldn't without a reason). From asyncio docs [4]:

  Don’t directly create Task instances: use the async() function or the
  BaseEventLoop.create_task() method.

The reason is probably to support Trollius (asyncio for Python 2) [5].

> Also, just so I can wrap my head around things, I was trying to mix
> concurrent and procedural programming in the code I provided, correct?
> Do you have any advice on how to avoid mixing types again in the
> future?

In short, the main issue was that your code executed some parts
sequentially e.g., A then B:

  yield from A
  yield from B # this is not reached until A finishes

that needed to be run concurrently:

  yield from asyncio.wait([A, B])

or in general, if you don't need to wait the results:

  asyncio.async(A)
  asyncio.async(B) 

  # ... yield later, to pass the control to the event loop
    (Task._step/_fut_waiter dance ☯)

Ask, if you have any specific questions about the code
http://pastebin.com/g08YaJyz 

There is a bug at the end. info('done') should be outside the loop
(improper indent).

[3] https://www.python.org/dev/peps/pep-0411
[4] https://docs.python.org/3/library/asyncio-task.html#asyncio.Task
[5] https://code.google.com/p/tulip/issues/detail?id=185


--
Akira




More information about the Python-list mailing list