osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Benefits of asyncio


On Tue, Jun 3, 2014 at 11:05 PM, Marko Rauhamaa <marko at pacujo.net> wrote:
> Chris Angelico <rosuav at gmail.com>:
>
>> I don't see how Marko's assertion that event-driven asynchronous
>> programming is a breath of fresh air compared with multithreading. The
>> only way multithreading can possibly be more complicated is that
>> preemption can occur anywhere - and that's exactly one of the big
>> flaws in async work, if you don't do your job properly.
>
> Say you have a thread blocking on socket.accept(). Another thread
> receives the management command to shut the server down. How do you tell
> the socket.accept() thread to abort and exit?
>
> The classic hack is close the socket, which causes the blocking thread
> to raise an exception.

How's that a hack? If you're shutting the server down, you need to
close the listening socket anyway, because otherwise clients will
think they can get in. Yes, I would close the socket. Or just send the
process a signal like SIGINT, which will break the accept() call. (I
don't know about Python specifically here; the underlying Linux API
works this way, returning EINTR, as does OS/2 which is where I
learned. Generally I'd have the accept() loop as the process's main
loop, and spin off threads for clients.) In fact, the most likely case
I'd have would be that the receipt of that signal *is* the management
command to shut the server down; it might be SIGINT or SIGQUIT or
SIGTERM, or maybe some other signal, but one of the easiest ways to
notify a Unix process to shut down is to send it a signal. Coping with
broken proprietary platforms is an exercise for the reader, but I know
it's possible to terminate a console-based socket accept loop in
Windows with Ctrl-C, so there ought to be an equivalent API method.

> The blocking thread might be also stuck in socket.recv(). Closing the
> socket from the outside is dangerous now because of race conditions. So
> you will have to carefully use add locking to block an unwanted closing
> of the connection.

Maybe. More likely, the same situation applies - you're shutting down,
so you need to close the socket anyway. I've generally found -
although this may not work on all platforms - that it's perfectly safe
for one thread to be blocked in recv() while another thread calls
send() on the same socket, and then closes that socket.  On the other
hand, if your notion of shutting down does NOT include closing the
socket, then you have to deal with things some other way - maybe
handing the connection on to some other process, or something - so a
generic approach isn't appropriate here.

> But what do you do if the blocking thread is stuck in the middle of a
> black box API that doesn't expose a file you could close?
>
> So you hope all blocking APIs have a timeout parameter.

No! I never put timeouts on blocking calls to solve shutdown problems.
That is a hack, and a bad one. Timeouts should be used only when the
timeout is itself significant (eg if you decide that your socket
connections should time out if there's no activity in X minutes, so
you put a timeout on socket reads of X*60000 and close the connection
cleanly if it times out).

> Well, ok,
>
>    os.kill(os.getpid(), signal.SIGKILL)
>
> is always an option.

Yeah, that's one way. More likely, you'll find that a lesser signal
also aborts the blocking API call. And even if you have to hope for an
alternate API to solve this problem, how is that different from hoping
that all blocking APIs have corresponding non-blocking APIs? I
reiterate the example I've used a few times already:

https://docs.python.org/3.4/library/logging.html#logging.Logger.debug

What happens if that blocks? How can you make sure it won't?

ChrisA