The Main Loop
2019
Asynchronous programming with libraries
class Dispatcher:
def __init__(self):
self.handlers = {}
def dispatch(self):
with select.poll() as demultiplexer:
for descriptor, handler in handlers.items():
if handler.should_read():
demultiplexer.register(descriptor, select.EPOLLIN)
if handler.should_write():
demultiplexer.register(descriptor, select.EPOLLOUT)
for descriptor, event in demultiplexer.select()
if event == select.EPOLLIN:
self.handlers[descriptor].handle_read()
if event == select.EPOLLOUT:
self.handlers[descriptor].handle_write()
class MainLoop:
def __init__(self):
self.dispatcher = Dispatcher()
self.running = False
def run(self):
self.running = True
while self.running:
self.dispatcher.dispatch()
def quit(self):
self.running = False
Xlib *
GLib
Qt
Twisted **
Tornado **
UV
Nodejs **
ReactPHP
Text
Text
* not really generic
** more than event loop
[censored]
Text
Text
Text
/* GLib */
g_child_watch_add(...)
g_dbus_get(...)
g_resolver_lookup_by_name_async(...)
// Qt
QProcess
QDbusConnection
QHostInfo
# twisted
esmtp_client = protocol.ClientFactory(protocol=smtp.ESMTPClient)
internet.TCPClient(esmtp_client)
// nodejs
client.query('SELECT $1::text AS message',
['Hello world!'],
(err, res) => {
console.log(err ? err.stack : res.rows[0].message)
})
Text
Text
Text
gboolean idle_task(gpointer user_data) {
/* ... */
return G_SOURCE_REMOVE;
}
int main() {
GMainLoop *loop = g_main_loop_new(NULL, false);
g_idle_add(idle_task, NULL);
g_main_loop_run(loop);
}
void idle_task(void) {
// ...
};
int main() {
QEventLoop loop;
QTimer::singleShot(0, idle_task);
loop.exec();
}
Is this a TETimer?
Text
Text
Text
bool DeathStar::really()
{
QMessageBox dialog(QMessageBox::Question,
"Destroy Alderaan?",
(QMessageBox::Apply |
QMessageBox::Ok |
QMessageBox::Retry))
int result = dialog.exec();
return result != QMessageBox::No;
}
block?
loop = GLib.MainLoop()
def wait():
GLib.timeout_add(1000, loop.quit)
loop.run()
Glib.idle_add(wait)
loop.run()
block?
Text
Text
Text
static uv_loop_t loop;
static uv_work_t work;
void work_callback(uv_work_t *work) {
/* runs in a thread */
work->data = compute_result();
}
void work_complete(uv_work_t *work, int status) {
/* runs in main loop */
}
uv_loop_init(&loop);
uv_queue_work(&loop, &work, work_callback, work_complete);
Text
Text
Text
gboolean callback(GIOChannel *channel,
GIOCondition condition,
gpointer user_data)
{
uint8_t buffer[1024];
gsize bytes_read;
GError error;
GIOStatus status = g_io_channel_read_chars(channel,
buffer, sizeof(buffer),
&bytes_read,
&error);
}
GIOChannel *channel = g_io_channel_unix_new(fd);
int fd = ...;
g_io_add_watch(channel, G_IO_IN, callback, NULL);
Text
Text
Text
/* libpq (postgresql) */
int PQsocket(const PGconn *conn);
int PQconsumeInput(PGconn *conn); /* readable */
int PQflush(PGconn *conn); /* writable, repeat until returns 0 */
/* libmosquitto (MQTT) */
int mosquitto_socket(struct mosquitto *mosq);
bool mosquitto_want_write(struct mosquitto *mosq);
int mosquitto_loop_read(struct mosquitto *mosq, int count); /* readable */
int mosquitto_loop_write(struct mosquitto *mosq, int count); /* writable */
int mosquitto_loop_misc(struct mosquitto *mosq); /* periodic */
/* libdbus */
int dbus_watch_get_unix_fd(DBusWatch *watch);
unsigned int dbus_watch_get_flags(DBusWatch *watch);
dbus_bool_t dbus_watch_handle(DBusWatch *watch, unsigned int flags);
Text
Text
Text
var promise = new Promise(function (resolve, reject) {
var c = new Connection();
c.on_connected(resolve);
c.on_timeout(reject);
c.connect('silvair.com', 443);
});
function great_success(result) { };
function utter_failure(error) { };
promise.then(great_success).catch(utter_failure)
Thank you
Questions?