Arrays em AdvPL – Parte 03

Introdução

No post anterior, vimos algumas particularidades e detalhes sobre os Arrays em AdvPL, referências, atribuições e afins. Agora, pra fechar com chave de ouro — e sair do Array — vamos ver dicas, mais considerações, boas práticas e cuidados com uso de Arrays.

Dimensões e Elementos

Segundo a documentação oficial, você pode criar quantas dimensões você quiser em um array. Embora não exista limite implícito, não exagere. Lembre-se do principio da simplicidade, e quanto mais dimensões tiver um array, maior será a sua ocupação na memória. Embora exista um limite máximo documentado de 100 mil elementos em um array, lembre-se que a soma do tamanho de memoria de cada conteúdo multiplicado pelo número de elementos pode chegar a números assombrosos. Cem mil elementos de 20 KB devem ocupar aproximadamente 2GB de memória.

Componentes que usam lista em formato de Array na interface, e não fazem paginação, por exemplo o tListBox, vão trafegar o array inteiro para a interface armazenar e renderizar na tela. Desse modo, não abuse do recurso, pois você pode penalizar a aplicação em memória — e posteriormente em desempenho.

Passagem de parâmetros para outros processos

Quando passamos um array como parâmetro para qualquer função do AdvPL, um array sempre será passado e recebido por referência. Quando precisamos “duplicar” um array, para que uma outra variável aponte para uma cópia do conteúdo, usamos a função ACLONE().

Quando realizamos passagem de parâmetros através de uma conexão nativa RPC do AdvPL, ou mesmo para um outro processo no mesmo servidor, usando por exemplo a função IPCGO, nestes cados o array é internamente CLONADO. Desse modo, o processo chamado que recebeu o array recebeu um “clone” ou uma cópia, e não uma referência ao array original.

Busca Binária em Array Ordenado

Quando você trabalha com um array ordenado, existem formas bem rápidas de se fazer uma busca neste array. A mais conhecida é chamada de “Busca binária”.  Na prática, o funcionamento é bem simples. Se o array está ordenado em ordem crescente, primeiro você determina a posição do seu primeiro elemento do array — posição 1 — e depois o último — posição igual ao tamanho do Array. Então, com estes dois números, você tira a média simples (soma e divide por 2) considerando o resultado inteiro, e descobre o número do elemento que está no meio da lista. Então você compara com o conteúdo que você está buscando. Se for igual, você achou. Se for menor, refaça a busca, definindo que a nova posição do fim dos dados é a posição do meio atual menos uma unidade, e caso seja maior, refaça a busca considerando a posição inicial de busca como sendo o meio atual mais uma unidade.

Assim, a cada comparação que você faz enquanto não encontra o elemento, simplesmente DESCARTA da busca METADE da lista. Isto realmente é eficiente, porém traz alguns cuidados adicionais:

  1. Para arrays pequenos, a diferença é realmente insignificante, não justifica o esforço de implementação.
  2. Se durante o processamento são feitas manutenções nos valores e conteúdos do Array, você deve garantir que o elemento seja reposicionado na ordem certa. Caso um novo elemento seja inserido no array, ele deve entrar ou ser movido para a posição correta para manter o Array em ordem. Você vai ter que primeiro fazer uma busca, chegar ao elemento mais próximo daquele que você vai inserir, e usar ASIZE / AINS ou AADD / AINS para aumentar o tamanho do array e inserir o novo elemento na posição adequada. Por mais que o algoritmo de sorteio (ASORT) seja bem rápido, inserir fora de ordem e depois reordenar o array a cada manutenção tem um custo elevado e pode prejudicar o desempenho do AdvPL.

Como eu já havia mencionado, para busca performática, inclusive sem a necessidade de ordenação, dos dados, podemos criar um objeto do tipo HASHMAP. Veja os artigos nos links abaixo, bem como o link da TDN com a documentação oficial

Informações adicionais de Ordenação

Quando usamos a opção de sorteio de arrays, e passamos um CodeBlock para customizar uma regra de ordenação, é bem mais performático fazer um ASORT em um array simples — onde cada elemento é o conteúdo a ser sorteado — sem usar um CodedBlock. Se você têm um array multidimensional, não têm escolha a não ser criar e passar como parâmetro o Codeblock de regra de ordenação.  O mesmo se aplica a um Array de dimensão simples, quando a ordenação desejada não seja ascendente (do menor para o maior) ou precise ser customizada.

Estouro de referências em objetos e blocos de código

Quando acrescentamos um objeto ou Codeblock dentro de um array, o elemento em questão passa a ser referenciado pelo índice do array, que aponta para aquela instância de objeto ou bloco de código. Cada novo elemento que nós acrescentamos no array que faz referência a um determinado objeto, o contador de referências daquele objeto ou Codeblock é incrementado. Neste caso, se criarmos um array de 20 mil linhas, e em uma determinada coluna do array sempre acrescentarmos o mesmo CodeBlock, ele será referenciado 20 mil vezes. Se eu clonar este array usando ACLONE, as referências entre os arrays é quebrada mas não as referências ao objeto ou Codeblock. Logo,  aquele Codeblock referenciado 20 mil vezes passa a ser referenciado 40 mil vezes. Vamos ao exemplo:

User Function aTest24()
Local aDados, aCopia
Local bBloco := {|x| conout(x) }
Local nTot := 20000

aDados := Array(nTot)
AFILL(aDados,bBloco)
aCopia := ACLONE(aDados)

Return

Ao executar este fonte, será criado um Array com 20 mil elementos, e cada um deles será alimentado com o mesmo Codeblock através da função AFILL. No momento de executar a função ACLONE(), deve ocorrer o erro abaixo:

Reference counter overflow ( over 32700 ) on tLocalEnv::IncRefs()

Existe um limite interno de contador de referências no Protheus, limitado internamente a 32700 referências. Logo, cuidado ao acrescentar muitas vezes o mesmo objeto ou bloco de código em arrays, pois caso o limite de referências seja atingido, seu código terá que ser refatorado para encapsular as referências em outro array, para este limite não ser atingido. Se o conteúdo referenciado em questão for um Objeto do AdvPL, a mensagem de erro será:

Reference counter overflow ( over 32700 ) on tClassInstance::addRef()

Conclusão

Acho que eu já torci bem a caixa de neurônios — também conhecida por “cabeça” — e não achei mais nada sobre Arrays em AdvPL.  Se eu encontrar mais alguma coisa sobre esse assunto, sai mais um post do forno !!!

Espero que estas informações sejam úteis, e desejo a todos TERABYTES DE SUCESSO !!! 😀

Referências

 

 

 

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s