23

Update

I asked the wrong question, rephrased (based on the great info on answers and comments):

Is there any good source on .net's async operations being real async, thus either IOCP or async(overlapped)? Is there any quick way to find out if several classes are doing so?

Example of not trusting framework developers blindly

The natural starting point for creating a FileStream is the static File.Open() method, the documentation for which mentions nothing about synchronicity of the FileStream that is created! Nor does it allow you to provide FileOptions (which are used to specify the magic FileOptions.Asynchronous flag).

Instead, the FileStream is created with FileOptions.None. Any asynchronous operations are quietly faked by the obliging implementation of the Stream base class, which merely wraps the corresponding synchronous method in a delegate and invokes it on the thread pool using the BeginInvoke() method.

This is a deviation from the usual ‘pit of success’ design philosophy, where everything in .NET seems to work as you think it would, without a need to closely read the documentation and/or gradually discover obscure catches and gotchas over time.


I've been trying to find information on the use of IO Completion Ports in .NET.

Is there any good way to know whether a given .NET class is using IO Completion Ports? (without having to run some tests every time you use a new class.

I tried the msdn docs for some classes and methods, and I couldn't find anything on it.

Even better, would be if there is some list out there with a list of classes using IOCP.

Community
  • 1
  • 1
eglasius
  • 35,831
  • 5
  • 65
  • 110
  • 4
    Are you planning to avoid such classes/methods? Or embrace them? What value do you gain by knowing, so long as they honour their contractual obligations? – Damien_The_Unbeliever Jan 29 '14 at 18:28
  • 1
    Embrace. The reason I'm looking at this, is because of an existing design that has its own threading and *no* use of .net's async. Of course there are various arguments that floated around, but the major one is whether calling into .net's async ends up being similar as far as the threading involved. IO Completion Ports changes that. Of course the real answer to that involves more detailed measurements and depending on that, setting a Proof of Concept and comparing. The code's performance is continually being improved, but this is an area that hasn't been explored. – eglasius Jan 29 '14 at 18:44
  • 3
    I'm not aware of any circumstance (much as @usr's answer) where the async I/O APIs aren't doing this. And I'd expect, if you find an I/O API in the .NET framework that *isn't* using these, it's for a bloomin' good reason (though I admit, that may not be documented anywhere). What you need to do is to "move up a level" - trust the framework developers to have "done the right thing" and rely on the abstractions that are exposed at that level - and stop worrying about *how* they've achieved them, user lower-level primitives. – Damien_The_Unbeliever Jan 29 '14 at 18:55
  • @Damien_The_Unbeliever personally I would have used the async methods, that is why I started the conversation about it, and I think the same as you and usr do.But you can't defend an argument, by saying, trust the framework developers did the right thing.I thought I had read on some methods getting IO Completion Ports in .net 3.5, but now that I go back and try to find it I only see references on improving the memory use (implying those did use IOCP :)). Of course thinking about it, if *all* async methods use either IOCP or other smart mechanism, then there is not much point saying it anywhere – eglasius Jan 29 '14 at 19:22
  • 3
    @eglasius the BCL is the best-designed class library of that size that I have ever seen. They must be auditing everything for correctness and usability in every release. I absolutely do trust them to get this essential thing right. I trust them more than me in this point. .NET is used for high-throughput servers all the time and they know it and test for that and optimize for that scenario. Threadless IO is absolutely essential to serving thousands of simultaneous requests. – usr Jan 30 '14 at 09:54
  • @usr I totally agree, but I am looking for a source I can quote on that being the design guidelines used in .net. For example, the .net async patterns documents in msdn make no mention on this, those just focus on the general pattern that applies to both IO and CPU bound APIs. I'll make it a bounty tomorrow to see if that helps :) – eglasius Jan 30 '14 at 13:07
  • A credible source: [There Is No Thread](http://blog.stephencleary.com/2013/11/there-is-no-thread.html). – noseratio Feb 01 '14 at 13:19
  • Did you read it until the end? "I think this documentation is out of date, or at least a little unclear. The default implementation of BeginRead does not call Read synchronously — Reflector shows that it calls Read by wrapping it in a delegate and calling BeginInvoke, which would result in it being called on a thread pool thread. This is an asynchronous call (with respect to the caller of BeginRead)." – Pedro.The.Kid Feb 04 '14 at 17:02
  • I did. The author of that text in msdn is clearly talking about the "modes of operation: synchronous I/O and asynchronous I/O" that are described on FileStream.BeginRead http://msdn.microsoft.com/en-us/library/zxt5ahzw.aspx What they mean is explained concisely in the FileStream's class doc: "When the IsAsync property is false and you call the asynchronous read and write operations, the UI thread is still not blocked, but the actual I/O operation is performed synchronously." http://msdn.microsoft.com/en-us/library/System.IO.FileStream(v=vs.110).aspx – eglasius Feb 05 '14 at 10:22
  • I think you need to check FILE_FLAG_OVERLAPPED flag using reflection http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx – mit Feb 06 '14 at 07:09

2 Answers2

19

I/O completion ports are a strong platform implementation detail, one that .NET cannot blindly depend on to be available. And it doesn't, it leaves it up to the CLR host to implement the glue to the operating system support for it. The underlying hosting interface is IHostIoCompletionManager, available since .NET 2.0

So if you want a hard guarantee the they actually get used then you need to get the source of the CLR host that you use. This is hard to come by, there are many and you'd need to apply to a job at Microsoft to get access to the source. Only the SSCLI20 host is available in source, it is dated and covers only the default host. Which was itself tweaked to allow the PAL to provide the I/O completion port, surely not actually present in the real CLR hosts you'd ever run on.

You were not specific about what platforms you consider. Some guesstimates:

  • ASP.NET: yes, I/O completion ports are a big deal for sockets
  • SQL Server: pretty likely, but no slamdunk, it has a knack for doing things differently
  • Desktop: yes, for any .NET version >= 2.0 that runs on the NT branch
  • Compact: definitely not
  • Micro: definitely not
  • XBox: unlikely, OS details are a big mystery
  • Silverlight: Windows version's CoreCLR.dll uses it but no ThreadPool.BindHandle
  • Phone7: similar to Silverlight
  • Phone8: big mystery, probably.

Emphasizing that these are merely educated guesses that are not backed by proof. The question is otherwise fairly strange, it is not like you'd have an alternative if you find out that async I/O was done by overlapped I/O.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • +1 that is great input, I hadn't considered there could be a difference in the platform in this area. The target platforms are mainly asp.net and the desktop (nt branch). My question is indeed weird, because I started thinking the use of IOCP was the only prove of real async I/O and that is not the only option. I am looking for sources that demostrate .net uses real IO async to peers that think at some point buried on the implementation details .net ends up just using a thread instead. – eglasius Feb 02 '14 at 14:41
  • @HansPassant what happened to the bounty? Shouldn't it be 500? ;-) – usr Feb 09 '14 at 22:23
18

Generally, the BCL only offers async APIs if they are implemented using async IO backed by the Windows kernel. Exposing async methods that do not use async kernel-IO would be the well-known async-over-sync anti-pattern which the BCL designers are surely aware of. This would not only be useless, but harmful for performance and misleading. They don't do that.

Windows can do async IO using IOCP or using regular overlapped IO. Both are efficient, asynchronous and therefore more scalable than blocking IO.

All of this is transparent to you. Rely on async being truly async, and sync being truly sync.

If in doubt, peek under the hood with Reflector. Whenever I have done this I have found confirmed what I just stated. I have yet to see a deviating case.

What you see with Reflector is that the BCL is calling the async versions of the relevant Win32 APIs. As an example, I'll examine files and sockets:

  • FileStream.BeginRead indirectly calls Win32Native.ReadFileNative with a pointer to a NativeOverlapped structure. The pointer is obtained by calling Overlapped.Pack. The completion callback is stored that way. It is impossible to track how the callback is called with Reflector because that part exists in the native part of the CLR. I cannot tell whether IOCP is in use but I can tell that async IO is in use.
  • Socket.BeginRead indirectly calls WSARecv. The code is quite complex. The BCL seems to be able to use overlapped IO as well as IOCP depending on the OS. The check is made in Socket.InitializeSockets. The decision what kind of IO to use is stored in Socket.UseOverlappedIO. If that variable is false, Socket.BindToCompletionPort is eventually called.

So for Sockets it is clearly IOCP on modern OS'es. For files I cannot tell.

I personally am not particularly interested in what kind of async IO is used as long as it is non-blocking. This is the case.

usr
  • 168,620
  • 35
  • 240
  • 369
  • 1
    "Generally"? Do you have a reference to back that up? I assume by "async APIs" you mean "async IO APIs"? – Peter Ritchie Jan 29 '14 at 18:34
  • 1
    Strictly speaking not all async IO in WinNT is IOCP. You can have async (overlapped) operations without binding them to a completion port. But +1 because the gist of what you say is true. – Remus Rusanu Jan 29 '14 at 18:41
  • @PeterRitchie the reference is me, my investigations and my reasoning. Nothing official AFAIK. – usr Jan 29 '14 at 18:58
  • @RemusRusanu yeah I wasn't sure about this which is why I said "generally, it is IOCP". I made that statement more clear. – usr Jan 29 '14 at 18:59
  • Thanks, you are answering the right question, not what I wrote originally. I hope someone has a reference, but now that I know what I should be looking for I may find something :) – eglasius Jan 29 '14 at 19:32
  • I'm curious how Reflector could have ever told you anything about IOCP. – Hans Passant Feb 01 '14 at 13:46
  • @HansPassant I have clarified the answer. For socket IO I could tell. I'm not sure what async IO method is used in other IO cases. – usr Feb 01 '14 at 14:18
  • What about .NET core? – Jesse Pepper Dec 07 '17 at 02:04