Utilizando concorrência nas consultas ao EPM Server

Vamos implementar o uso da biblioteca padrão do Python concurrent.futures para fazer consultas ao EPM Server, trazendo possíveis ganhos de peformance, principalmente quando se possui muitas variáveis a serem pesquisadas.

In [10]:
import epmwebapi as epm
import numpy as np
import datetime

##Método para não expor usuário e senha do EPM no código fonte
import getpass
user = input('EPM user:')
password = getpass.getpass("EPM password:")

#crie o objeto de conexão informando os endereços do EPM Webserver(Authentication Port e WEB API Port), usuário e senha.
connection = epm.EpmConnection('http://localhost:44333', 'http://localhost:44332', user, password)

#periodo da consulta 
end_date = datetime.datetime.now()
ini_date= end_date - datetime.timedelta(days=2)
queryPeriod = epm.QueryPeriod(ini_date,end_date)

#configuração da agregação
processInterval = datetime.timedelta(minutes=10)
aggDetails = epm.AggregateDetails(processInterval, epm.AggregateType.Interpolative)

#função para buscar dados
def get_basicvariable_agg(epmconnection, bvname, period, aggregatedetails):
    
    bv = epmconnection.getDataObjects([bvname])
    data = bv[bvname].historyReadAggregate(aggregatedetails, period)
    print(bvname+' lenght:{}'.format(str(len(data))))
    return data

#20 basic variables que serão pesquisadas
bvname = ['ADM_Temperature','EPMDev_Temperature','E3Dev_Temperature', 
          'TI_Temperature', 'PowerDev_Temperature', 'TechnicalSupportTemperature',
         'Auditorio_Temperature','Treinamento_Temperature','MobileDev_Temperature',
         'MeetingRoom11th_Temperature', 'MeetingRoom10th_Temperature','MeetingRoom12th_Temperature',
         'TIServidores_Temperature', 'Dev12th_Temperature', 'Dev11th_Temperature', 
         'ADM_TemperatureSP', 'MeetingRoom10th_TemperatureSP', 'EPMDev_TemperatureSP', 
         'PowerDev_TemperatureSP', 'MeetingRoom11th_TemperatureSP']
EPM user:elipse\kotres
EPM password:········

Executando a consulta sequencialmente em um laço

Verificamos que o retorno ocorre na ordem da lista bvname.

In [11]:
%%time

data = []

for bv in bvname:    
    data.append(get_basicvariable_agg(connection, bv, queryPeriod, aggDetails))        
    
ADM_Temperature lenght:288
EPMDev_Temperature lenght:288
E3Dev_Temperature lenght:288
TI_Temperature lenght:288
PowerDev_Temperature lenght:288
TechnicalSupportTemperature lenght:288
Auditorio_Temperature lenght:288
Treinamento_Temperature lenght:288
MobileDev_Temperature lenght:288
MeetingRoom11th_Temperature lenght:288
MeetingRoom10th_Temperature lenght:288
MeetingRoom12th_Temperature lenght:288
TIServidores_Temperature lenght:288
Dev12th_Temperature lenght:288
Dev11th_Temperature lenght:288
ADM_TemperatureSP lenght:288
MeetingRoom10th_TemperatureSP lenght:288
EPMDev_TemperatureSP lenght:288
PowerDev_TemperatureSP lenght:288
MeetingRoom11th_TemperatureSP lenght:288
Wall time: 5.54 s

Executando a consulta com concorrência

  • Para esse caso houve redução de cerca de 73% no tempo total da consulta.
In [12]:
%%time

import concurrent.futures
from concurrent import futures

#máximo de consultas paralelas
MAX_WORKERS = 10

data = []

#executa no máximo 10 consultas paralelas e no mínimo a quantidade de variáveis a serem consultadas (se forem menos de 10).
workers = min(MAX_WORKERS, len(bvname))

#usamos a clausula with para ter certeza que as threads serão fechadas logo após o termino da sua execução
with futures.ThreadPoolExecutor(workers) as executor:
    future_to_get_bv = {executor.submit(get_basicvariable_agg, connection, bv, queryPeriod, aggDetails): bv for bv in bvname}    
    for future in concurrent.futures.as_completed(future_to_get_bv):
        data.append(future.result())
ADM_Temperature lenght:288
TI_Temperature lenght:288
Auditorio_Temperature lenght:288
MobileDev_Temperature lenght:288E3Dev_Temperature lenght:288

PowerDev_Temperature lenght:288
MeetingRoom11th_Temperature lenght:288
TechnicalSupportTemperature lenght:288EPMDev_Temperature lenght:288
Treinamento_Temperature lenght:288

MeetingRoom10th_Temperature lenght:288
MeetingRoom12th_Temperature lenght:288
Dev11th_Temperature lenght:288PowerDev_TemperatureSP lenght:288
ADM_TemperatureSP lenght:288
EPMDev_TemperatureSP lenght:288MeetingRoom11th_TemperatureSP lenght:288

TIServidores_Temperature lenght:288MeetingRoom10th_TemperatureSP lenght:288


Dev12th_Temperature lenght:288
Wall time: 1.5 s