I've done lots of development in C#/.Net, and the asynchronous story has always been there from day one (admittedly the API's have changed significantly over the years from begin/end to events, to Task<T>
with async
/await
). For the last year or so I've been developing with Node.js which does all I/O asynchronously and uses a single threaded event loop model. Recently I was working on a project where we were using Ruby, and for one part of the application, I felt that it made sense to make a whole bunch of web requests asynchronously, and was surprised to find that the asynchronous story in Ruby is vastly different. The only way to do any asynchronous I/O is by using the EventMachine
.
My question comes down to this: Why is it that in .Net (and from what I can tell this is true for Java/JVM as well) there's no need for an event loop, and I can fire off an asynchronous request at any time, yet in languages like Ruby/Python, I need to resort to eventmachine/twisted respectively? I feel like there's some fundamental thing about how asynchronous I/O works that I'm not understanding.
The event loop is the core of every asyncio application. Event loops run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses. Application developers should typically use the high-level asyncio functions, such as asyncio.
Event Loop's job is to watch Callback Queue and Call Stack, whenever Call Stack is empty and we have called in Callback Queue. The event loop will move calls to Call Stack and execute them in succession.
The event loop is what allows Node. js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible. Since most modern kernels are multi-threaded, they can handle multiple operations executing in the background.
For loops. Combining async with a for (or a for...of ) loop is possibly the most straightforward option when performing asynchronous operations over array elements. Using await inside a for loop will cause the code to stop and wait for the asynchronous operation to complete before continuing.
My question comes down to this: Why is it that in .Net (and from what I can tell this is true for Java/JVM as well) there's no need for an event loop, and I can fire off an asynchronous request at any time, yet in languages like Ruby/Python, I need to resort to eventmachine/twisted respectively?
I think that's because Ruby/Python (and seamlessly, Node.js as well) want to make a developer's life easier by imposing single-threaded model for the application's core loop. With event machine, the completion callbacks of the async I/O routines are serialized and queued to be executed on the same thread, so the developer doesn't have to worry about thread safety.
I can't speak for Java, but in .NET we have control over this with synchronization context. Check Stephen Cleary's "It's All About the SynchronizationContext". It's quite easy to replicate the concept of event machine in .NET (in fact, that's automatically done for UI applications). A custom implementation of the serializing synchronization context might look like AsyncPump
from Stephen Toub's "Await, SynchronizationContext, and Console Apps". IMO, this would be a direct match to Ruby's event machine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With