> But if you bring this up to most Windows people they tell you to use IO completion ports, which are totally different and require the core of the program to be redesigned
IO completion ports and epoll both require the programs flow logic to be designed for them. If a program has been designed for synchronous IO, a redesign is required to take advantage of any asynchronous IO pattern. There's no magic fairy dust that allows you to magically drop "asynchronous" to an otherwise synchronous program.
The reactor pattern (Windows overlapped IO) is - at least theoretically - more scalable than the proactor pattern (Linux epoll/aio).
Under the proactor pattern (Linux epoll/aio) the process must indicate it's desire to perform an IO operation. The OS will notify the process through a callback/event when the IO resource is available for the operation, and must then perform the actual operation. However at that point there is no guarantee that all of the IO will be completed - the OS will inform you how many bytes were actually read/written, and it is your responsibility to wait for the next "ready" event before trying again.
Under the reactor pattern (Windows overlapped IO) the process asks the OS to perform the IO operation directly. The operation is started by the OS while the call returns immediately. When the operation has been carried out, the OS notifies the process through a callback/event. There is no complexity in managing partially transfers - the transfer in the responsibility of the OS and you'll receive notice when it's completed. IO completion ports is actually a thread pool dedicated to IO ops, and queuing is built-in.
The proactor pattern (Linux/epoll) requires a context switch between the IO resource becoming ready for the operation and the actual operation (higher latency). If transfers are partially completed - e.g. large transfers - you'll have extra context switches for each remaining transfer operation (lower throughput).
The reactor pattern (Windows) allows the OS to directly complete the operation without a preceding context switch (lower latency), only notifying the process when done, thus avoiding unnecessary context switches even for large buffers (higher throughput).
Both approaches require the program to be deliberately designed to support asynchronous IO. However, the Windows API was always designed with overlapped (asynchronous) IO in mind, Windows IO completion ports was designed in NT from the start. The problem was always (for both platforms) how to coach the developers to actually leverage the asynchronous APIs as opposed to the simpler-to-understand synchronous APIs.
The new Windows Runtime API takes it a step further and requires virtually all IO to be asynchronous (there simply are no synchronous versions any more). That is coupled with programming language innovations like async/await (C#/VB.NET) which makes it very easy indeed to take advantage of this.
This is exactly what I'm talking about. The attitude is that overlapped IO is "better" and screw you if you don't want to redesign your existing software to use it.
First, here's a real example where it isn't better. You have some app which holds a thousand some sockets and receives packets infrequently. With epoll you need one buffer when the odd packet arrives regardless of which socket is ready. With overlapped IO the amount of buffer memory you need is more by a factor of a thousand because each idle socket still requires a buffer to be allocated to it.
But that's not really the point. Having overlapped IO available is fine -- it is better for some applications. The problem is not having epoll, not only because epoll is sometimes better, but because it makes portability unnecessarily difficult. Because in most cases the performance difference between the two is irrelevant and the important criteria is how much work I'm going to have to do to make them both behave the same way on each platform.
>With overlapped IO the amount of buffer memory you need is more by a factor of a thousand because each idle socket still requires a buffer to be allocated to it.
Use the select function then. Wait for completion of that instead. No need to allocate buffers for sockets that receive messages infrequently.
epoll is a horribly designed API. It should absolutely not be replicated on other platforms.
There is: Overlapped IO: http://msdn.microsoft.com/en-us/library/windows/desktop/ms68...
> But if you bring this up to most Windows people they tell you to use IO completion ports, which are totally different and require the core of the program to be redesigned
IO completion ports and epoll both require the programs flow logic to be designed for them. If a program has been designed for synchronous IO, a redesign is required to take advantage of any asynchronous IO pattern. There's no magic fairy dust that allows you to magically drop "asynchronous" to an otherwise synchronous program.
The reactor pattern (Windows overlapped IO) is - at least theoretically - more scalable than the proactor pattern (Linux epoll/aio).
Under the proactor pattern (Linux epoll/aio) the process must indicate it's desire to perform an IO operation. The OS will notify the process through a callback/event when the IO resource is available for the operation, and must then perform the actual operation. However at that point there is no guarantee that all of the IO will be completed - the OS will inform you how many bytes were actually read/written, and it is your responsibility to wait for the next "ready" event before trying again.
Under the reactor pattern (Windows overlapped IO) the process asks the OS to perform the IO operation directly. The operation is started by the OS while the call returns immediately. When the operation has been carried out, the OS notifies the process through a callback/event. There is no complexity in managing partially transfers - the transfer in the responsibility of the OS and you'll receive notice when it's completed. IO completion ports is actually a thread pool dedicated to IO ops, and queuing is built-in.
The proactor pattern (Linux/epoll) requires a context switch between the IO resource becoming ready for the operation and the actual operation (higher latency). If transfers are partially completed - e.g. large transfers - you'll have extra context switches for each remaining transfer operation (lower throughput).
The reactor pattern (Windows) allows the OS to directly complete the operation without a preceding context switch (lower latency), only notifying the process when done, thus avoiding unnecessary context switches even for large buffers (higher throughput).
Both approaches require the program to be deliberately designed to support asynchronous IO. However, the Windows API was always designed with overlapped (asynchronous) IO in mind, Windows IO completion ports was designed in NT from the start. The problem was always (for both platforms) how to coach the developers to actually leverage the asynchronous APIs as opposed to the simpler-to-understand synchronous APIs.
The new Windows Runtime API takes it a step further and requires virtually all IO to be asynchronous (there simply are no synchronous versions any more). That is coupled with programming language innovations like async/await (C#/VB.NET) which makes it very easy indeed to take advantage of this.