Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It can be difficult to implement well on nix systems. async/await works so well in C# because IOCP in Windows is completion based. I/O on current nix OSes is readiness based (epool/kqueue).

I implemented a completion based wrapper ontop of libev and libaio in C but could never quite nail it.

It's worth mentioning that IOCP can be used on any fd in Windows, whereas Linux epoll loop can only be used for sockets. There is a caveat to that however, you can use the epoll loop if you use eventfd with some effectively undocumented behavior of the aio subsystem that allows you to register an eventfd with your aio context. There are drawbacks to this though, you have to use O_DIRECT and aligned writes. In Windows you can use IOCP to do async buffered writes...

Thankfully much smarter people work on Rust and hopefully they manage to make a completion based IO system that is portable across the operating systems.



I don't see why the IO model would be a fundamental issue here. Fundamentally, async/await is about automating inversion of control, which is a mechanical program transformation.


I also don't see that as a problem either. There are 2 seperate issues:

a) Be able to await the result Future/Task objects instead of attaching callbacks to them. This is done by source code rewriting and has no dependencies on an IO system.

b) Having IO libraries that return future objects. You can do that with IOCP as well as with unix poll based architectures. Might be a little bit easier with IOCP, but it's no deal breaker. I already did an implementation for epoll once. You simply spin up an eventloop in any thread. Any IO read/write returns a future object, posts the work to the eventloop and as soon as the work completes the eventloop completes the future.


The parents are saying that a transformation target that supports IOCP is easier to support than one that supports epoll.

Think about this the way that you might think about GCC backends -- some architectures make certain things easier than others.

Or how an abstraction layer like MonoGame papers over the fundamental differences between OpenGL and DirectX -- some abstractions perform better with one or the other subsystem.


Unfortunately most of what you want to do with await/async is IO based, the IO model matters a lot if you want it to be scalable. Without kernel support trying to build a completion based API is not very performant. Trying to emulate it in a library proved painful, especially when trying to do IO on files.


I'm not sure that's true. The same kind of mechanical transformation that gives await/async also leads to Python-style generator functions, and I wind up using them all the time for all kinds of iteration tasks, not just I/O (or at least, not just async I/O).


You're conflating two distinct concepts.

Certainly, code rewriting to support continuation is a factor in both C#-style await and generator functions, but they are not the same thing.

Much of the motivation behind async I/O is to reduce the number of active threads blocked on I/O. Blocked threads means stack space consumed, kernel transitions, and potentially CPU contention if too many threads become runnable at once, and then start fighting over mutexes or cache.

In this way of looking at the world, you don't want to block for any I/O. That's what the GP is getting at.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: