Figure 1: Showing the Process of a client request in terms of a browser and web server
As shown in Figure 1:
Looking at Figure 1 again, let see what would happen if the CGI executable were to be replaced by an ISAPI extension application.
An ISAPI application, does not spawn a new process after it has been called the first time by a request. Rather, it runs in the server's process space, thus reducing both memory overhead and startup time. Only a single copy of this server extension is loaded and is then shared if additional client requests for the same application come in. Furthermore, once an ISAPI application is loaded into the process space, it stays loaded until IIS is stopped and restarted, or until some unspecified period when IIS decides to unload it. This means new requests for the ISAPI will get much quicker responses and resource utilization is kept low due to a single instance model, rather than a multiple instance model in the case of a CGI.
All in all, this speed improvement is a strong argument for using ISAPI to do anything that requires back-end server processing over a CGI. If one were to look at CGI scripts or any other scripting mechanism, its easy to see that these types of applications will perform far slower than even CGI executables as they are interpreted rather than compiled. One should also note, that the interpreter needs to be loaded in memory to do its job as well. So resource utilization is much higher in scripting mechanisms such as, Perl, ASP etc. and performance is poor due to the interpreted nature.
Designing High-Performance ISAPI Applications ISAPI is the highest-performance interface for Web applications. If you create an ISAPI extension or filter, it will outperform ASP scripts or even components performing similar tasks. However, the inherent speed of the ISAPI interface does not mean that you can ignore performance and scalability considerations. Indeed, ISAPI cannot utilize much of the application support services provided by ASP and COM. If you would like your ISAPI application to maintain session state, for instance, much of that session-state functionality would have to be implemented by you.
ISAPI is the highest-performance interface for Web applications. If you create an ISAPI extension or filter, it will outperform ASP scripts or even components performing similar tasks.
However, the inherent speed of the ISAPI interface does not mean that you can ignore performance and scalability considerations. Indeed, ISAPI cannot utilize much of the application support services provided by ASP and COM. If you would like your ISAPI application to maintain session state, for instance, much of that session-state functionality would have to be implemented by you.
Quote continues... Here are some suggestions for improving the scalability and performance of your ISAPI extensions: Avoid ISAPI filters, unless adding an ISAPI filter is absolutely necessary to your application architecture. You should especially avoid filters that perform processing on raw incoming or outgoing data. If you determine that a filter is absolutely necessary, be sure to carefully optimize the main code paths through the filter event notification code. Create your own worker thread pool, so that the main I/O threads can be freed to accomplish other tasks. This option is available only for ISAPI extensions, and not for ISAPI filters. For more information about how IIS processes requests, see IIS Request Processing. A sample that demonstrates a worker thread pool, implemented in an ISAPI extension, is available in ISAPI Examples. Consider using asynchronous operations and I/O completion ports, when feasible. IIS supports asynchronous reading and writing by using the I/O completion ports, available in Windows NT 4.0, and Windows 2000 or later. Depending on the type of I/O operations being performed, asynchronous operations can make better use of the CPU time available, and generally work particularly well when implemented using a worker thread pool. ISAPI extensions should use the Win32 TransmitFile function, exposed by the HSE_REQ_TRANSMIT_FILE ServerSupportFunction. Use Connection: Keep-Alive headers. Keeping persistent HTTP connections will provide better performance than using non-persistent connections, in most cases. Minimize need for thread synchronization by maintaining state information with the request context. If thread synchronization is required, make sure that critical sections are kept short. If your ISAPI application uses the heap intensively, consider other heap alternatives. Intensive use of the Windows? heap can cause resource contention. Several memory allocation alternatives are worth exploring, including: Heap Partitioning, accomplished by creating multiple custom heaps, in addition to the default process heap. Each custom heap would then be controlled by a separate, non-global lock, and lock contention would be reduced. Cached Allocation, which involves using custom allocation operations that operate at a middle layer between the object users and the heap. Calls to the Win32 heap are made infrequently, and only for large memory blocks. These blocks are then subdivided and managed by the custom allocator. Stack Allocation, using the C run-time function _alloca to allocate memory for your objects on the stack instead of the heap. This method is feasible only for relatively small objects, because the space available on the stack is limited. In addition, your newly allocated object will be available only within the current functions, or functions called by that function. Once the current function returns, the storage allocated on the stack will be lost. Object Encapsulation, accomplished by simply incorporating a buffer as a member data structure of a class. This buffer is then used for tasks that would otherwise require accesses to the Win32 heap. Avoid using global locks within your ISAPI, if possible. Global locks can often adversely affect scalability.
An intersting page on the Microsoft site compares ASP and ISAPI performance, scalability etc. Check it out here