Confidential • Synchronization is required when accessing shared data structures • Choosing the right locking granularity is hard. • Risk of deadlocking. • (Theads have some overhead: memory, context switching.) -> Instead of using locks, people often use queues (message passing) for inter-thread communication. What’s wrong with threads?
Confidential Threads vs coroutines Threads Coroutines Pre-emptive: The operating system decides when to context switch to another task Co-operative: The tasks themselves decide when to hand over control. Can switch to other thread at any point in time. Only switches to other coroutine when there’s an “await” Tell when it’s impossible to go to another thread (using locks). Tell when it’s possible to go to another thread (using await).
Confidential • Dispatch table An abstraction on top of event loops I/O completion event Callback File 1 ready for reading func1 Stdin ready for reading func2 Network socket 1 ready for writing func3 Received mouse event func4 Received keyboard event func5 Etc…
Confidential Event loops: The good things - Everything runs in one thread: - But only one callback at a time. - No complicated synchronization (data locking) - Little risk of deadlocking. - Easy to debug. - Handle many connections in parallel. - Idle connections barely consume anything in an event driven system. - Cheaper then one thread per connection.
Confidential while True: wait_for_any_fd_to_become_ready() handle_fd_callback() Don’t mix with blocking I/O - Callbacks can’t do any kind of blocking I/O, like `read()`, `recv()`, etc… - Instead, they should do it asynchronously, and register the file descriptor with a callback in the event loop.
Confidential • Imagine logging to a remote server. • Logging can eventually happen in every function. • So, every function needs to become async. No: use an asynchronous queue: - On one end, push the messages into the queue (queue.put_nowait) - On the other end, have one coroutine consume the queue and flush to the remote server. Don’t turn every call into an async call
Confidential • Asyncio is a great concurrency pattern for I/O heavy applications. • Not the easiest to begin with, but when things become complex, often easier than threading • Important pitfalls: • Don’t mix with blocking I/O. • Don’t turn every function into an async function. Conclusion jonathan_s jonathanslenders