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.
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)
#função para buscar dados
def get_basicvariable_rawvalues(epmconnection, bvname, period):
bv = connection.getDataObjects([bvname])
data = bv[bvname].historyReadRaw(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']
Verificamos que o retorno ocorre na ordem da lista bvname.
%%time
data = []
for bv in bvname:
data.append(get_basicvariable_rawvalues(connection, bv, queryPeriod))
%%time
import concurrent.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_rawvalues, connection, bv, queryPeriod): bv for bv in bvname}
for future in concurrent.futures.as_completed(future_to_get_bv):
data.append(future.result())