where/how can I find whether a .net class uses IOC

2019-02-03 02:09发布

问题:

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.

回答1:

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.



回答2:

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.