<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jason Madden (Posts about event loop)</title><link>https://seecoresoftware.com/</link><description></description><atom:link href="https://seecoresoftware.com/blog/categories/event-loop.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2021 &lt;a href="mailto:jason@seecoresoftware.com"&gt;Jason Madden&lt;/a&gt; </copyright><lastBuildDate>Sat, 04 Dec 2021 18:43:37 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>gevent's hub</title><link>https://seecoresoftware.com/blog/2018/05/gevent-hub.html</link><dc:creator>Jason Madden</dc:creator><description>&lt;figure&gt;&lt;img src="https://c1.staticflickr.com/9/8665/16605819942_8fb5626c93_n.jpg"&gt;&lt;/figure&gt; &lt;div&gt;&lt;p&gt;The &lt;em&gt;hub&lt;/em&gt; is an important part of &lt;a class="reference external" href="https://seecoresoftware.com/blog/categories/gevent.html"&gt;gevent&lt;/a&gt;, but
aside from a few sentences in the high-level description &lt;a class="reference external" href="http://www.gevent.org/intro.html#event-loop"&gt;of the event
loop&lt;/a&gt;, and the &lt;a class="reference external" href="http://www.gevent.org/api/gevent.hub.html#module-gevent.hub"&gt;API
documentation&lt;/a&gt;, not a
lot has been written about the hub, its purpose, or how it does what
it does. This post aims to change that and answer questions like:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;What is the hub?&lt;/li&gt;
&lt;li&gt;How does the hub run the event loop?&lt;/li&gt;
&lt;li&gt;How do greenlets do IO? That is, how do they let the event loop run,
while letting other greenlets run, and then pick right back up where
they blocked?&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- TEASER_END --&gt;
&lt;div class="contents topic" id="contents"&gt;
&lt;p class="topic-title first"&gt;Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#what-is-a-hub" id="id6"&gt;What is a hub?&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#the-hub-is-a-greenlet" id="id7"&gt;The hub is a greenlet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#the-hub-runs-the-event-loop" id="id8"&gt;The hub runs the event loop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#getting-out-of-the-hub" id="id9"&gt;Getting out of the hub&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#wait-how-did-we-get-in-the-hub-in-the-first-place" id="id10"&gt;Wait, how did we get in the hub in the first place?&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#some-code" id="id11"&gt;Some code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#a-few-loose-threads-get-it" id="id12"&gt;A few loose threads (get it?)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="sidebar"&gt;
&lt;p class="first sidebar-title"&gt;Implementation Details Alert&lt;/p&gt;
&lt;p class="last"&gt;This post discusses implementation details of gevent 1.3. These
details generally should not be relied upon other than as
&lt;a class="reference external" href="http://gevent.org"&gt;documented&lt;/a&gt;, as they may change in the future.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-is-a-hub"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id6"&gt;What is a hub?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's begin with what gevent's official documentation has to say about
the hub:&lt;/p&gt;
&lt;blockquote&gt;
When a function from gevent's API wants to
block, it obtains the &lt;tt class="docutils literal"&gt;gevent.hub.Hub&lt;/tt&gt; instance—a special
greenlet that runs the event loop—and switches to it (it is said
that the greenlet &lt;em&gt;yielded&lt;/em&gt; control to the Hub). If there's no
&lt;tt class="docutils literal"&gt;gevent.hub.Hub&lt;/tt&gt; instance yet, one is automatically created.&lt;/blockquote&gt;
&lt;p&gt;Not exactly self explanatory. The API documentation doesn't add much
to that.&lt;/p&gt;
&lt;p&gt;To try to understand what that means, let's break it into chunks.&lt;/p&gt;
&lt;div class="section" id="the-hub-is-a-greenlet"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id7"&gt;The hub is a greenlet&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The hub is a greenlet. &lt;a class="reference external" href="https://greenlet.readthedocs.io"&gt;greenlets&lt;/a&gt;
are one implementation of &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Green_threads"&gt;green threads&lt;/a&gt;. They're like a
"normal" operating system &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Thread_(computing)"&gt;thread&lt;/a&gt; in that each
greenlet has a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Call_stack"&gt;call stack&lt;/a&gt; (the C call stack of the
Python interpreter, plus the Python call stack) and represents one flow
of control through a program. They are different in that many
greenlets can be associated with a single operating system thread.
&lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#f1" id="id1"&gt;[1]&lt;/a&gt; This has the important effect that only one greenlet attached
to a thread is ever actually executing at any given time.&lt;/p&gt;
&lt;p&gt;Another way in which greenlets differ from typical operating system
threads is that they are &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Cooperative_multitasking"&gt;cooperatively scheduled&lt;/a&gt;, instead of
preemptively scheduled. That is, in order for another greenlet to be
able to run, the greenlet that is currently running must &lt;em&gt;choose&lt;/em&gt; to
give up control to it; this is called "switching". Moreover, it must
actually &lt;em&gt;choose&lt;/em&gt; the greenlet it wants to run next! &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#f2" id="id2"&gt;[2]&lt;/a&gt; To do so,
the current greenlet invokes the &lt;a class="reference external" href="https://greenlet.readthedocs.io/en/latest/#switching"&gt;switch method of the destination
greenlet&lt;/a&gt; When
a greenlet switch occurs, the call stack of the current greenlet is
saved away, the call stack of the destination greenlet is put in
place, and execution resumes where the destination greenlet left off.
&lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#f3" id="id3"&gt;[3]&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-hub-runs-the-event-loop"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id8"&gt;The hub runs the event loop&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ok, so the hub is a greenlet—a cooperatively scheduled call stack or
thread of execution. That thread of execution is running the event
loop.&lt;/p&gt;
&lt;p&gt;Here's how gevent's documentation describes an event loop:&lt;/p&gt;
&lt;blockquote&gt;
Instead of blocking and waiting for socket operations to complete
(a technique known as polling), gevent arranges for the operating
system to deliver an event letting it know when, for example, data
has arrived to be read from the socket. Having done that, gevent
can move on to running another greenlet, perhaps one that itself
now has an event ready for it. This repeated process of
registering for events and reacting to them as they arrive is the
event loop.&lt;/blockquote&gt;
&lt;p&gt;In a visual sense, an event loop looks something like this (this is
a very high-level overview of libuv's event loop; don't worry too much
about the specific details or terminology &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#f4" id="id4"&gt;[4]&lt;/a&gt;):&lt;/p&gt;
&lt;img alt="https://docs.libuv.org/en/v1.x/_images/loop_iteration.png" src="https://docs.libuv.org/en/v1.x/_images/loop_iteration.png"&gt;
&lt;p&gt;"Running the event loop" means that the hub enters the top of that
loop and cycles through it &lt;em&gt;forever&lt;/em&gt;. The event loops that gevent
supports are implemented in C, so entering the top of the loop means
making a C function call &lt;a class="footnote-reference" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#f5" id="id5"&gt;[5]&lt;/a&gt;. That C function call is not expected to
return (because it's an infinite loop).&lt;/p&gt;
&lt;p&gt;"Registering for events" is done with objects called "watchers". Each
watcher object is looking for one particular event to happen.&lt;/p&gt;
&lt;p&gt;How, then, do other greenlets—the ones that actually read and write
socket data and otherwise make up your application—get to run? This
is where it gets interesting.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-out-of-the-hub"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id9"&gt;Getting out of the hub&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Look at that diagram again. See those blocks that start with "Call",
like "Call pending callbacks", or "Run", like "Run due timers"? Those
blocks are our loophole. That's when the event loop—while still
inside its single C function—gives gevent a chance to do something,
such as respond to an IO event or handle a scheduled event (timer).&lt;/p&gt;
&lt;p&gt;For each event that gevent might want to handle, it has created a
watcher and given it to the event loop. Each watcher is associated
with a &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Callback_(computer_programming)"&gt;callback&lt;/a&gt;: a
function that the event loop will call when the desired event occurs.
(Giving a watcher to the event loop and associating it with a callback
is referred to as "starting" the watcher.) That function can do just
about anything. If that function happens to invoke
&lt;tt class="docutils literal"&gt;destination_greenlet.switch()&lt;/tt&gt;, then whoosh, just like that, the
hub and the event loop it's somewhere in the middle of running is
paused (its C call stack is saved away) and some other greenlet takes
off running.&lt;/p&gt;
&lt;div class="section" id="wait-how-did-we-get-in-the-hub-in-the-first-place"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id10"&gt;Wait, how did we get in the hub in the first place?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We just saw how we can get &lt;em&gt;out&lt;/em&gt; of the hub when its busy running the
event loop: invoke a callback that calls &lt;tt class="docutils literal"&gt;greenlet.switch&lt;/tt&gt;. But how
did we start running the event loop in the hub in the first place?&lt;/p&gt;
&lt;p&gt;Let's look back to the quoted description of the hub:&lt;/p&gt;
&lt;blockquote&gt;
When a function from gevent's API wants to
block, it obtains the &lt;tt class="docutils literal"&gt;gevent.hub.Hub&lt;/tt&gt; instance—a special
greenlet that runs the event loop—and switches to it. If there's no
&lt;tt class="docutils literal"&gt;gevent.hub.Hub&lt;/tt&gt; instance yet, one is automatically created.&lt;/blockquote&gt;
&lt;p&gt;So any gevent blocking function (such as
&lt;tt class="docutils literal"&gt;gevent.socket.socket.read()&lt;/tt&gt;) is going to go switch into the hub.
If it's the first time the hub has been entered, the hub will start up
the event loop. Otherwise, if the hub was already running the event
loop, it will pick up where &lt;em&gt;it&lt;/em&gt; last left off and either respond to
the next event (IO, timer) by calling another callback, or let the
event loop wait for the next event.&lt;/p&gt;
&lt;p&gt;You can imagine it something like a game of ping pong, with the hub on
one side of the table, and all the other greenlets on the other side.
The hub hits the ball over the net to a greenlet who (eventually) hits
it back, and then the hub hits the ball to another greenlet, and so
on, &lt;em&gt;ad infinitum&lt;/em&gt;.&lt;/p&gt;
&lt;div class="section" id="some-code"&gt;
&lt;h4&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id11"&gt;Some code&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now we know enough to look at some code and put the pieces together to
understand how it works under the covers.&lt;/p&gt;
&lt;p&gt;Most blocking functions end up implementing their half of the game
by calling &lt;a class="reference external" href="http://www.gevent.org/api/gevent.hub.html#gevent.hub.Hub.wait"&gt;Hub.wait()&lt;/a&gt;. For
example, here's basically what &lt;tt class="docutils literal"&gt;gevent.socket.socket.recv()&lt;/tt&gt; looks
like:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-3"&gt;&lt;/a&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-4"&gt;&lt;/a&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-5"&gt;&lt;/a&gt;        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-6"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;EWOULDBLOCK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-7"&gt;&lt;/a&gt;                &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;a name="rest_code_184cb0d99d47410f89cf203bc56dc251-8"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_read_event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;That code is looping until we can actually read some data. If we try
to read and we fail because there's nothing to read, hand things over
to the event loop using &lt;tt class="docutils literal"&gt;hub.wait()&lt;/tt&gt;, which will switch into the
hub, make sure the event loop is watching this socket, and then carry
on.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;Hub.wait&lt;/tt&gt;, in turn, is implemented something like this (this is a
dramatically simplified example; the real thing is safer and uses a &lt;a class="reference external" href="http://www.gevent.org/api/gevent.hub.html#gevent.hub.Waiter"&gt;Waiter&lt;/a&gt;):&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# Hub.wait()&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-2"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# `watcher` is an event-loop object with a callback. When the&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-3"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# event it's waiting for happens, its callback gets called.&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-4"&gt;&lt;/a&gt;    &lt;span class="n"&gt;current_greenlet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getcurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-5"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# The callback for this event will switch back to&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-6"&gt;&lt;/a&gt;    &lt;span class="c1"&gt;# this current greenlet&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-7"&gt;&lt;/a&gt;    &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_greenlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Ask the event loop to watch this&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-9"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# Start running the hub.&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-10"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-11"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# Once we get here, it's because the watcher's callback&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-12"&gt;&lt;/a&gt;        &lt;span class="c1"&gt;# fired and this greenlet got switched into.&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-13"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;# Let the blocking code continue, its event is ready&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-14"&gt;&lt;/a&gt;    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_4ce8b24e00c847f6ae993eed3f56f8c9-15"&gt;&lt;/a&gt;        &lt;span class="n"&gt;watcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="a-few-loose-threads-get-it"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id12"&gt;A few loose threads (get it?)&lt;/a&gt;&lt;/h2&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;What happens when a greenlet finishes execution?&lt;/dt&gt;
&lt;dd&gt;Control is returned to its parent greenlet. gevent arranges for
the hub to be the parent of every greenlet it runs, so when a
greenlet dies, whether through successful completion or an
uncaught exception, the hub gets a chance to run the event loop.&lt;/dd&gt;
&lt;dt&gt;What happens when we want to start a new greenlet?&lt;/dt&gt;
&lt;dd&gt;&lt;a class="reference external" href="http://www.gevent.org/api/gevent.html#gevent.spawn"&gt;gevent.spawn()&lt;/a&gt; creates a
new greenlet and schedules it to start running in the next
iteration of the event loop. It does this by, you guessed it,
setting up an event watcher with a callback that's
&lt;tt class="docutils literal"&gt;new_greenlet.switch()&lt;/tt&gt;. That event watcher is a "prepare"
watcher, a type of event that becomes available at the start of
each iteration of the loop.&lt;/dd&gt;
&lt;dt&gt;How are gevent locks and timeouts implemented?&lt;/dt&gt;
&lt;dd&gt;You'll have to wait for &lt;a class="reference external" href="https://seecoresoftware.com/blog/2018/05/implementing-gevent-locks.html"&gt;another post&lt;/a&gt; for that! But if you want to
look into the implementation, this post should provide most of the
background you need.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p class="rubric"&gt;Footnotes&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="f1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;For simplicity's sake, we'll assume there's only one
operating system thread in the process.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;In most cases. When a greenlet finishes, control is
automatically handed back to its parent greenlet.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;This is quite a fascinating technical accomplishment and
involves &lt;a class="reference external" href="https://github.com/python-greenlet/greenlet/tree/master/platform"&gt;assembly code for each supported platform&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;In particular, do not worry about the difference between
"run" and "call." Neither libuv nor libev &lt;em&gt;really&lt;/em&gt; run their
event loop in exactly this fashion. The important point is
that it is a loop that does the same things over and over, in the
same order each time.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="f5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label"&gt;&lt;col&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="https://seecoresoftware.com/blog/2018/05/gevent-hub.html#id5"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;In the case of libuv, that's &lt;a class="reference external" href="http://docs.libuv.org/en/v1.x/loop.html#c.uv_run"&gt;uv_run()&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</description><category>blocking</category><category>details</category><category>event loop</category><category>gevent</category><category>greenlet</category><category>hub</category><category>implementation</category><category>python</category><guid>https://seecoresoftware.com/blog/2018/05/gevent-hub.html</guid><pubDate>Fri, 18 May 2018 18:40:00 GMT</pubDate></item></channel></rss>