Sobrecarga ao chamar uma função componente versus código embutido - ColdFusion

9

Estou diagnosticando um problema de desempenho ao gerar um arquivo CSV com cerca de 50.000 linhas e reduzi-o a uma única função que é usada uma vez por linha.

Depois de muita confusão, descobri que há uma sobrecarga no uso da função, em vez de colocar a lógica diretamente no loop - minha pergunta é: por que?!

A função em questão é muito simples, aceita um argumento de string e passa para um switch / case com 15 opções - retornando a string resultante. Eu coloquei um monte de temporizadores em todo o lugar e descobri que muito (não todos) do tempo que esta chamada de função leva entre 0 e 200 ms para executar ... no entanto, se eu colocar o mesmo código em linha, ele fica a 0 em cada iteração.

Tudo isso aponta para uma questão fundamental na minha compreensão da instanciação de objetos e eu gostaria de receber alguns esclarecimentos.

Eu sempre tive a impressão de que, se eu instanciasse um componente no topo de uma página, ou mesmo se eu instanciasse um escopo persistente como Aplicativo ou Sessão, ele seria colocado na memória e as chamadas subseqüentes para funções dentro esse componente seria muito rápido. Parece, no entanto, que há uma sobrecarga para chamar essas funções e enquanto estamos falando apenas de alguns milissegundos, quando você tem que fazer isso, 50.000 vezes, isso se soma rapidamente.

Além disso, parece que isso consome recursos. Eu não sou particularmente bem versado na forma como a JVM usa memória, eu li sobre ela e joguei com configurações e tal, mas é um tópico esmagador - especialmente para aqueles de nós sem experiência em desenvolvimento Java. Parece que ao chamar o método sobre o código embutido, às vezes, o serviço ColdFusion apenas recolhe e a solicitação nunca termina. Outras vezes, de fato, completa, embora muito devagar. Isso sugere que a solicitação pode ser concluída apenas quando o servidor possui os recursos para manipulá-la - e, portanto, que a própria chamada do método está consumindo memória ... (?)

Se, de fato, a chamada de um método tiver uma sobrecarga anexada, tenho um grande problema. Não é realmente possível colocar todo este código em linha (embora a função em questão seja simples, há muitas outras funções que eu preciso usar) e isso vai contra tudo o que eu acredito como desenvolvedor !! / p>

Então, qualquer ajuda seria apreciada.

Apenas para maior clareza e porque tenho certeza de que alguém vai pedir, aqui está o código em questão:

EDITAR: Como sugerido, mudei o código para usar uma pesquisa struct em vez de CFSwitch - abaixo está o código alterado para referência, no entanto, há também um aplicativo de teste em links pastebin na parte inferior.

Dentro do método init:

    <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'
    } />

Função sendo chamada:

<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>

Conforme solicitado, criei um aplicativo de teste para replicar este problema:

link - Application.cfc

link - TestCom.cfc (Coloque na pasta 'com' fora do webroot)

link - index.cfm

    
por Gary Stanton 16.04.2014 в 14:36
fonte

2 respostas

2

A chamada de função será sempre mais lenta que o código inline em qualquer idioma. É por isso que há inline palavra-chave em C ++ e, no JVM, existe o otimizador JIT, que irá embutir funções para você, se julgar necessário.

Agora, o ColdFusion é outra camada no topo da JVM. Portanto, uma função no CF não é uma função na JVM, então as coisas não se traduzem 1: 1 no ponto de vista do otimizador JIT. Uma função CFML é, na verdade, compilada em uma classe Java. Além disso, escopos como arguments , local (hashtables Java) são criados em cada chamada. Isso leva tempo e memória e, portanto, sobrecarga.

  

... se eu instanciá-lo em um escopo persistente, como aplicativo ou   Sessão, em seguida, seria colocado na memória e chamadas subsequentes para   funções dentro desse componente seriam muito rápidas

Seria mais rápido do que instanciar uma nova instância com certeza, mas não será "muito rápido", especialmente quando você a chamar em um loop apertado.

Em conclusão, a função inline e se ainda não for rápida o suficiente, localize a parte mais lenta do código e escreva-a em Java.

    
por Henry 16.04.2014 / 20:12
fonte
0

Apenas uma nota de lado aqui, já que o Railo usa classes internas em vez de classes independentes completas, é mais rápido se você escrever em um estilo que tenha muitas funções pequenas. Nos meus experimentos, os dois mecanismos funcionam de maneira semelhante ao código inline básico. O Adobe ColdFusion presta-se a grandes funções se você precisar eliminar o desempenho sob carga. Com a JVM sendo incapaz de inline as funções do ColdFusion durante a compilação, você nunca terá o benefício de o compilador ser inteligente com seu código.

Isso é especialmente importante se você criou um aplicativo que usa uma tonelada de getters / setters explícitos e descobre que seu tráfego aumenta de um volume pequeno para um volume alto. Todas essas pequenas funções o deixarão de joelhos versus menos grandes funções de "deus".

De mais lento a mais rápido, com um teste básico, executamos 100.000 iterações:

Adobe ColdFusion (muitas pequenas funções) (200X mais lento que o Java) Railo (muitas pequenas funções) (60X mais lento) ColdFusion / Railo (todo o código inline em uma função gigante) (10X mais lento) Classe Java nativa (mais rápida)

    
por J.T. 20.08.2014 / 22:44
fonte