Вопрос

I've been diagnosing a performance issue with generating a CSV containing around 50,000 lines and I've narrowed it down to a single function that is used once per line.

After a lot of messing about, I've discovered that there is an overhead in using the function, rather than placing the logic directly in the loop - my question is: Why?!

The function in question is very simple, it accepts a string argument and passes that to a switch/case block containing around 15 options - returning the resulting string. I've put a bunch of timers all over the place and discovered that a lot (not all) of the time this function call takes between 0 and 200 ms to run... however if I put the exact same code inline, it sits at 0 on every iteration.

All this points to a fundamental issue in my understanding of object instantiation and I'd appreciate some clarification.

I was always under the impression that if I instantiate a component at the top of a page, or indeed if I instantiate it in a persistent scope like Application or Session, then it would be placed into memory and subsequent calls to functions within that component would be lightning fast. It seems however, that there is an overhead to calling these functions and while we're only talking a few milliseconds, when you have to do that 50,000 times it quickly adds up.

Furthermore, it seems that doing this consumes resources. I'm not particularly well versed in the way the JVM uses memory, I've read up on it and played with settings and such, but it's an overwhelming topic - especially for those of us with no Java development experience. It seems that when calling the method over inline code, sometimes the ColdFusion service just collapses and the request never ends. Other times it does indeed complete, although way too slowly. This suggests that the request can complete only when the server has the resources to handle it - and thus that the method call itself is consuming memory... (?)

If indeed the calling of a method has an overhead attached, I have a big problem. It's not really feasible to move all of this code inline, (while the function in question is simple, there are plenty of other functions that I will need to make use of) and doing so goes against everything I believe as a developer!!

So, any help would be appreciated.

Just for clarity and because I'm sure someone will ask for it, here's the code in question:

EDIT: As suggested, I've changed the code to use a struct lookup rather than CFSwitch - below is amended code for reference, however there's also a test app in pastebin links at the bottom.

Inside the init method:

    <cfset  Variables.VehicleCategories = {
            'T1'    : 'Beetle'
        ,   'T1C'   : 'Beetle Cabrio'
        ,   'T2'    : 'Type 2 Split'
        ,   'T2B'   : 'Type 2 Bay'
        ,   'T25'   : 'Type 25'
        ,   'Ghia'  : 'Karmann Ghia'
        ,   'T3'    : 'Type 3'
        ,   'G1'    : 'MK1 Golf'
        ,   'G1C'   : 'MK1 Golf Cabriolet'
        ,   'CADDY' : 'MK1 Caddy'
        ,   'G2'    : 'MK2 Golf'
        ,   'SC1'   : 'MK1/2 Scirocco'
        ,   'T4'    : 'T4'
        ,   'CO'    : 'Corrado'
        ,   'MISC'  : 'MISC'
    } />

Function being called:

<cffunction name="getCategory" returntype="string" output="false">
    <cfargument name="vehicleID" required="true" type="string" hint="Vehicle type" />

    <cfscript>
        if (structKeyExists(Variables.VehicleCategories, Arguments.VehicleID)) {
            return Variables.VehicleCategories[Arguments.VehicleID];
        }
        else {
            return 'Base SKUs';
        }
    </cfscript>
</cffunction>

As requested, I've created a test application to replicate this issue:

http://pastebin.com/KE2kUwEf - Application.cfc

http://pastebin.com/X8ZjL7D7 - TestCom.cfc (Place in 'com' folder outside webroot)

http://pastebin.com/n8hBLrfd - index.cfm

Это было полезно?

Решение

Function call will always be slower than inline code in Any language. That's why there's inline keyword in C++, and in JVM land there is JIT optimizer that will inline functions for you if it deems necessary.

Now ColdFusion is yet another layer on top of JVM. Therefore a function in CF is not a function in JVM, so things don't translate 1:1 at the JIT optimizer standpoint. A CFML function is actually compiled down to a Java class. Also, scopes like arguments, local (Java hashtables) are created on every invocation. Those takes time and memory and therefore overhead.

...if I instantiate it in a persistent scope like Application or Session, then it would be placed into memory and subsequent calls to functions within that component would be lightning fast

It'd be faster than instantiating a new instance for sure, but it's not going to be "lightning fast" especially when you call it in a tight loop.

In conclusion, inline the function and if it's still not fast enough, locate the slowest part of the code and write it in Java.

Другие советы

Just a side note here, since Railo uses inner classes instead of complete independent classes, it is faster if you write in such a style as to have many small functions. In my experiments, both engines perform similarly with basic inline code. Adobe ColdFusion lends itself to large god functions if you need to squeak out performance under load. With the JVM being unable to inline ColdFusion functions during compilation, you'll never get the benefit of the compiler being smart with your code.

This is especially important if you created an application that uses a ton of explicit getters/setters and you find your traffic increasing from small volume to high volume. All those little functions will bring you to your knees vs. having fewer large "god" functions.

Slowest to fastest with one basic test we ran of 100,000 iterations:

Adobe ColdFusion (many small functions) ( 200X slower than Java) Railo (many small functions) (60X slower) ColdFusion / Railo (all code inline in one giant function) (10X slower) Native Java Class (fastest)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top