Paralelismo, concorrência e escrita em arquivo

237 views
Skip to first unread message

Eduardo Cuducos

unread,
Nov 26, 2016, 2:52:25 PM11/26/16
to python-brasil

Galera, ontem tomei uma surra. Pedi ajuda pra todo mundo. Fui escutando, estudando, errando até que consegui resolver o problema. Não sei se da melhor forma — por isso estou postando aqui. Vai ser um email longo. Se a preguiça estiver por perto é melhor deixar para lá…

Contexto

A operação Serenata de Amor é um projeto de código aberto e dados abertos. Lá temos a geolocalização de todas as empresas onde os deputados gastaram com dinheiro público. O Guilherme, um colaborador do projeto que não conheço pessoalmente mas já admiro, mandou um pull request com um script em Python que tenta descobrir se a nota fiscal apresentada é de um “puteiro” — entre aspas mesmo. Oficialmente chamamos de sex related places: casas de entretenimento adulto de alta rotatividade.

Ele usou a API do Google Places e fez uma lista com 12 palavras-chave para achar esses lugares. O script, então, segue essa lógica:

  1. Pega as coordenadas geográfica de uma empresa do nosso dataset
  2. Faz 12 requisições à API, uma para cada palavra chave (a desgraçada da API não aceita OR para pesquisar por mais de uma palavra-chave), perguntando se tem algum lugar dessa categoria nas redondezas da coordenada geográfica da empresa
  3. Caso tenha um ou mais resultados, ele escolhe o resultado cujas coordenadas geográficas sejam mais próximas das coordenadas geográficas da empresa e faz uma 13ª requisição à API para pegar detalhes sobre esse lugar (nome, por exemplo)
  4. Por fim, grava isso em um arquivo (um novo dataset)

Problema

Temos atualmente (esse número deve subir em breve) mais de 60 mil empresas no nosso dataset. 60 mil empresas dentro dessa lógica significa 780 mil requisições à API. Graças à grana do Catarse temos como pagar pela API, esse não é o problema. O problema é o tempo que demora para fazer 780 mil requisições, tratar os resultados e gravar em arquivo. Esse é o calo.

Pelas minhas contas levaríamos mais de 1 semana rodando o script. Isso em si não é problema, o problema é internet estável, necessidades de pausa imposta pela API (limite de 150 mil requests diários), erros etc.

Então resolvi refatorar essa contribuição.

Estratégias

  1. A primeira coisa foi abrir o arquivo no modo 'a' (mais precisamente, no modo 'at' já que estamos usando o módulo lzma), escrever uma linha e fechar o dito cujo. Isso me garante que eu não preciso ter todos os resultados para terminar a escrita do arquivo, e me garante que caso o arquivo fique grande demais eu ocupe memória com ele.
  2. A segunda coisa foi paralelizar as requisições. Das 13 que podem acontecer para cada empresa, as 12 primeiras podem ser simultâneas; inicio todas de uma vez, em paralelo, com o grequests (ou seja, com gevent por debaixo dos panos).
  3. A terceira foi a surra! Tentei usar multiprocessamento para processar o fluxo todo de mais de uma empresa em paralelo já que o fluxo de processamento de uma empresa não depende do fluxo de processamento de outra empresa. Aí esbarrei feio na dificuldade de escrever em arquivo no meio dessa multiprocessamento.

    a. Primeiro tentei combinar o asyncio com o ProcessPoolExecutor; fiz uns testes curtos e pareceu funcionar (por funcionar entendam: escrever linhas no arquivo de resultados assim que cada empresa é processada, sem esperar o término da execução do script); mas depois de mais de 6h rodando fui ver e não tinha nada no arquivo — não entendi o porquê, mas essa versão do script está aqui.

    b. A versão atual do arquivo é um tanto complexa. Implementei duas filas: uma para todas as empresas, e outra para todos os sex related places encontrados. Aí começo um encadeamento de processos (multiprocess.Process) para processar e gerenciar as filas: um processo extraí todas as empresas do dataset de empresas e adicionar as empresas na fila de empresas; outros processos vão processando a fila de empresas, fazendo as consultas na API; por fim um último processo cuida da fila de lugares encontrados, pegando cada um deles e escrevendo em arquivo. Parece que funcionou, rodei uns testes curtos, mas preciso esperar o respiro da API para fazer um teste de algumas horas. Esse emaranhado de filas e processor está aqui.

Dúvidas

  1. gevent está resolvendo, teria alguma vantagem refatorar para usar oasyncio nativo?
  2. Alguém entende o porquê de a versão com asyncio ProcessPoolExecutor não estar escrevendo para arquivo conforme os resultados estão chegando? (no caso da execução por algumas horas, pelo menos)
  3. Alguém sabe se a versão nova com filas e processos vai ou não funcionar, e — principalmente — o porquê?
  4. Essa complexidade a que cheguei é mesmo necessária? É esse o único jeito combinar essas três coisas: paralelismo, concorrência e escrita de arquivo?
  5. Eu deveria ter ficado no caminho mais simples (processar uma empresa por vez, gravar em arquivo e passar para a próxima) ao invés de ter tentando acelerar as coisas co paralelismo, concorrência, multiprocessamento etc.?
  6. E, claro, alguma outra forma de fazer essas 780 mil de requisições mais rapidamente, salvando os dados em arquivo conforme os resultados forem chegando?

O email é longo, e o script também (versão atual aqui, caso tenha perdido o link ali em cima). Mas me disponho a apresentar o script a qualquer interessado em uma call, adoraria parear etc. e tal. Alguém me acode?

Muito obrigado,

Marcos Thomaz

unread,
Nov 26, 2016, 3:16:37 PM11/26/16
to python...@googlegroups.com
Não vi tão "a fundo" o código, mas se você forçar a escrita do arquivo a cada vez que escrever no stream já não resolveria o problema da perda dos dados?
Tipo, a linha 268 (writer.writerow(contents)) você escreve o conteúdo no stream porém não é persistido no arquivo. Tente adicionar duas linhas abaixo (mesma endentação da linha 268): 
flush()
os.fsync() 

Isso deve "forçar" a escrita no arquivo (pelo menos foi assim que resolvemos um problema com a gravação em arquivo de alguns dados vindos de uns sensores aqui).


--
--
------------------------------------
Grupo Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar
 
<*> Para visitar o site do grupo na web, acesse:
http://groups.google.com/group/python-brasil
 
<*> Para sair deste grupo, envie um e-mail para:
python-brasil+unsubscribe@googlegroups.com

---
Você recebeu essa mensagem porque está inscrito no grupo "Python Brasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para python-brasil+unsubscribe@googlegroups.com.
Para mais opções, acesse https://groups.google.com/d/optout.



--


Marcos Thomaz da Silva
Analista de Tecnologia da Informação

Avraham Serour

unread,
Nov 26, 2016, 4:17:45 PM11/26/16
to python...@googlegroups.com
porque você não guarda os dados em banco de dados? foi para isso que inventaram banco de dados? para que ficar tendo do de cabeça com arquivos?

leve em consideração o sqlite também

Avraham Serour

unread,
Nov 26, 2016, 4:33:38 PM11/26/16
to python...@googlegroups.com
eu já trabalhei com processpool e outras soluções para fazer tarefas em paralelo, e para um workload desse tamanho descrito eu sugiro usar celery, vai ter menos dor de cabeça e vai ser muito mais facil de distribuir até mesmo entre maquinas.

muito legal a ideia do projeto, para outras pessoas que nunca ouviram falar sobre a iniciativa: https://github.com/datasciencebr/serenata-de-amor

Avraham

Eduardo Cuducos

unread,
Nov 26, 2016, 4:41:29 PM11/26/16
to python...@googlegroups.com
Muito obrigado, Avraham e Marcos (e valeu pelo apoio ao projeto, Avraham!). Vamos às respostas:

se você forçar a escrita do arquivo a cada vez que escrever no stream já não resolveria o problema da perda dos dados?

Olha, para ser sincero não sabia que depois da saída do contexto, do with ( o file handler close() implícito) a escrita não estava feita ainda… interessante isso. Vou testar e estudar o flush()os.fsync() para entender melhor!

porque você não guarda os dados em banco de dados? foi para isso que inventaram banco de dados? para que ficar tendo do de cabeça com arquivos?

Não pensei nisso até agora por um motivo simples: nas melhores práticas de data science se trabalha com datasets, por ser dados puros, mais fáceis de serem usados para reproduzir a análise de alguém etc. Mas deixando o purismo de lado o banco de dados pode ser sim um passo interessante para construir o dataset — principalmente o SQLite! 

Vou pensar então em usar Celery, ou Redis para ter mais controle sobre esse fluxo.

Muito obrigado pelas boas sugestões ; )

Avraham Serour

unread,
Nov 26, 2016, 5:03:30 PM11/26/16
to python...@googlegroups.com
o celery pode usar o redis como backend para o controle de filas, é só uma biblioteca que vai te ajudar a colocar tarefas no redis e rodar workers consumindo as tarefas.
você pode rodar celery workers em varias maquinas na mesma rede ligadas ao mesmo redis, você pode colocar umas maquinas a mais temporárias e depois matar elas quando o batch terminar

você ainda pode usar datasets em arquivos para fazer as analises de data science, uma coisa não exclui a outra.
Mas realmente não deixe purismo de lado, você deve ter apenas uma fonte unica de verdade ou o DB ou os arquivos com datasets

Imagino duas formas:

1 - Usando o DB como fonte de verdade:
antes de rodar a analise faça uma especie de dump do banco de dados para o seu formato de dataset, aquivo, dicionario, array de numpy ou pandas

2 - Arquivos como fonte de verdade:
crie um db temporário antes de começar o batch e use para processar os 60k lugares, depois de terminar faça um dump para o seu arquivo de dataset e apague o DB


pode passar o link para o PR em questão?

Eu dei uma lida no projeto e vi que as notas fiscais são coisa de 1TB, é isso mesmo? qual o formato do arquivo?

o sqlite é muito util e fácil de se trabalhar mas se essa for sua ordem de grandeza para o DB recomendo usar postgres, realmente introduz mais uma dependência ao projeto mas não vai ter problemas de performance com um volume de dados desse tamanho

independente de qual DB você decidir usar eu sugiro usar algum ORM para facilitar a sua vida e de colaboradores, entre todos os que existem eu sugiro usar o ORM do django porque um belo dia alguem vai querer criar uma interface web, fazendo isso você deixa a porta aberta para uma contribuição nesse sentido.

porque guardar os dados em arquivos? qual o tipo de analise está sendo feita?

Avraham


Nilo Menezes

unread,
Nov 27, 2016, 10:19:03 AM11/27/16
to Python Brasil
Opa,

Eu fiz uns testes com o lzma e não tive problemas.
Na linha 227, você sobrescreve o self.write com o processo em si:
self.write = Process(target=self.write)

Acho que teu write nem está executando por isso. Vale a pena checar.
O arquivo fica com zero bytes pq você cria e depois não escreve nele :-(

Quanto a concorrência, no caso do arquivo, vi apenas um processo escrevendo no arquivo.
Neste caso, não precisa fazer lock.

Atenciosamente,

Nilo Menezes
------------------- Nilo Menezes (@lskbr) Livro: http://python.nilo.pro.br/

Nilo Menezes

unread,
Nov 27, 2016, 10:55:14 AM11/27/16
to Python Brasil
Opa, 

Esqueci de responder a parte async.

  1. gevent está resolvendo, teria alguma vantagem refatorar para usar oasyncio nativo?
Provavelmente não, mas eu converteria para asyncio e Python 3.5 com await para tornar mais coerente evitar misturar gevent com asyncio.
  1. Alguém entende o porquê de a versão com asyncio e ProcessPoolExecutor não estar escrevendo para arquivo conforme os resultados estão chegando? (no caso da execução por algumas horas, pelo menos)
Eu respondi essa questão em outro email, mas para outra versão do código... erro meu.
Se cair no caso de vários processos escrevendo no mesmo arquivo, proteja a seção com: 
fcntl.lockf(lz, fcntl.LOCK_EX) e fcntl.lockf(lz, fcntl.LOCK_UN)
O lzma cria um bloco toda vez que voce fechar o arquivo. Se a linha for muito pequena, o prefixo do bloco é gigante.
Eu colocaria o loop dentro do write_to_csv para não chamá-lo para cada place.

Quanto a nada gravar, você já olhou o retorno de near_to?
Se tiver um motel, a função retorna None e isso faz com que o write_to_csv não seja chamado.
Na linha 171, eu tenho a impressão que você retorna 1 lugar apenas (closest -> place). Na linha 228 você parece esperar uma lista de places.
É difícil ajudar sem ter os dados de retorno.

  1. Alguém sabe se a versão nova com filas e processos vai ou não funcionar, e — principalmente — o porquê?
Me perdi completamente.
  1. Essa complexidade a que cheguei é mesmo necessária? É esse o único jeito combinar essas três coisas: paralelismo, concorrência e escrita de arquivo?
É uma forma sim. Acho que você nem precisaria do Multiprocess, apenas no asyncio e do executor mesmo. Fora a compatação lzma, o trabalho é i/o bound, caso ideal pro async i/o.
  1. Eu deveria ter ficado no caminho mais simples (processar uma empresa por vez, gravar em arquivo e passar para a próxima) ao invés de ter tentando acelerar as coisas co paralelismo, concorrência, multiprocessamento etc.?
Tudo depende se a maneira mais simples resolve seu problema eu não. Otimizar o que não precisa dá trabalho.
Uma questão que não ficou claro para mim e se são vários arquivos por empresa ou se é por data.

  1. E, claro, alguma outra forma de fazer essas 780 mil de requisições mais rapidamente, salvando os dados em arquivo conforme os resultados forem chegando?
Você está quase lá, tem apenas que resolver uns bugs.
Quanto as 780 mil requisições, como você vai fazer com a quota? Não são apenas 150 mil por dia?

[]

Nilo

Em sábado, 26 de novembro de 2016 20:52:25 UTC+1, Eduardo Cuducos escreveu:

Francisco Souza

unread,
Nov 27, 2016, 12:19:39 PM11/27/16
to python...@googlegroups.com
Opa Eduardo,
Pensando mais na estrutura do programa do que nos detalhes de
implementação, você poderia separar o processamento de cada empresa do
processamento de todas as empresas no final: você tem um "job"
processando cada empresa e no final esse job escreve um arquivo, no
final dessa etapa você teria um arquivo por empresa e poderia começar
a combinar esses arquivos. E você pode combinar de 2 em 2 em paralelo.

Tendo isso pronto você pode começar a otimizar: começar a segunda
etapa assim que você tiver pelo menos dois arquivos, ao invés de
esperar a primeira etapa finalizar.

Mas se usar um banco de dados é uma opção, é bem mais simples: a
primeira etapa escreve tudo no banco e deixa o sgbd gerenciar as
escritas concorrentes, a segunda etapa faz uma query no banco (2ª
sugestão do Avraham).

Por último, o mais simples de tudo: usar flock para serializar a
escrita do arquivo e rodar tudo em paralelo.

Abraços,
Francisco
> --
> --
> ------------------------------------
> Grupo Python-Brasil
> http://www.python.org.br/wiki/AntesDePerguntar
>
> <*> Para visitar o site do grupo na web, acesse:
> http://groups.google.com/group/python-brasil
>
> <*> Para sair deste grupo, envie um e-mail para:
> python-brasi...@googlegroups.com
>
> ---
> Você recebeu essa mensagem porque está inscrito no grupo "Python Brasil" dos
> Grupos do Google.
> Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie
> um e-mail para python-brasi...@googlegroups.com.

Luciano Ramalho

unread,
Nov 28, 2016, 2:00:28 AM11/28/16
to python-brasil
Cuducos, recentemente eu fiz por hobby um scraping e queria fazer em paralelo mas tinha o problema de coordenar a escrita de arquivos daí percebi que era muito melhor escrever os dados em um BD. Usei o Redis, que é super fácil de usar. Eu gosto do SQLite mas ele não resolvia exatamente a parte que eu precisava: o gerenciamento de dados para vários processsos concorrentes. Para isso você precisa mesmo de um servidor de banco de dados rodando em seu próprio processo. Poderia ser um PostgreSQL, mas o Redis é super simples de instalar e usar, e eu queria brincar com ele (era hobby).

Outra coisa: é pésssimo usar no mesmo programa mais do que um framework para fazer a mesma coisa, especialmente para fazer programação concorrente: é como ter dois maestros em uma orquestra, simplesmente não funciona. Pode funfar por acidente nos primeiros testes, mas logo vai tornar o programa impossível de manter e impossível de identificar gargalos de desempenho.

Sugiro fortemente usar só gevent ou só asyncio. Use o que for mais confortável para você.

[ ]s
Luciano












>
> ---
> Você recebeu essa mensagem porque está inscrito no grupo "Python Brasil" dos
> Grupos do Google.
> Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie

> Para mais opções, acesse https://groups.google.com/d/optout.

--
--
------------------------------------
Grupo Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar

<*> Para visitar o site do grupo na web, acesse:
    http://groups.google.com/group/python-brasil

<*> Para sair deste grupo, envie um e-mail para:
Você está recebendo esta mensagem porque se inscreveu no grupo "Python Brasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para python-brasil+unsubscribe@googlegroups.com.
Para obter mais opções, acesse https://groups.google.com/d/optout.



--
Luciano Ramalho
|  Author of Fluent Python (O'Reilly, 2015)
|     http://shop.oreilly.com/product/0636920032519.do
|  Technical Principal at ThoughtWorks
|  Twitter: @ramalhoorg

Diego Nascimento

unread,
Nov 28, 2016, 3:03:54 AM11/28/16
to python...@googlegroups.com
Fiz um projeto pessoal que manipula arquivos grandes, ele lê os arquivos, processa e escreve um novo arquivo com os dados processados que serão consumidos posteriormente por uma aplicação.

Testei algumas linguagens, acabava que python ou ruby ficava bem lento, impraticável, então usei o lua, com luajit e fiz assim, o arquivo que ia ser lido era dividido em várias partes com split, era executado um processo para cada parte e cada um devolvia um arquivo já processado, no final, com tudo já concluído, eu juntava tudo em um só, automatizei e ficou bom, você pode fazer de uma forma parecida com o python, não envolve complexidade e fica super rápido.

Marcelo Valle (BLOOMBERG/ LONDON)

unread,
Nov 28, 2016, 8:38:44 AM11/28/16
to python...@googlegroups.com
Eduardo, 

Muito legal tanto o problema tecnico quanto a aplicacao pratica. Show de bola mesmo, adorei o projeto de voces, parabens! Senti uma inveja branca aqui, um dia quero criar um projeto diferente com uma ideia nessa linha e tentar ser financiado no catarse tbm. Se voces tiverem alguns issues no seu projeto github que estejam com dificuldades de resolver, posso tentar submeter umas PRs, se for ajudar.

No caso do seu problema abaixo, um comentario antes de te dar uma solucao: usar a API multiprocessing vai te ajudar a usar 100% dos recursos de uma maquina. Contudo, se o volume de dados que voce quer processar eh muito grande, voces deveriam considerar usar ferramentas de big data. Uma que talvez ajude no seu caso eh o python twisted - https://twistedmatrix.com/trac/wiki/SuccessStories . Outra coisa que voceh pode considerar sao ferramentas de map /reduce, como o spark, gravando o resultado final em uma base nosql, como HBase ou Cassandra.

No caso do problema abaixo, voceh quer processar coisas em paralelo e gravar em um arquivo no final. Entao pra te ajudar a chegar numa solucao, pense:
  • Se seu processo eh IO bound ou CPU bound. Ele passar mais tempo fazendo contas e usando CPU ou na maior parte do tempo ele faz IO? Qual o gargalo do seu processo?
  • Quantas operacoes em paralelo voce pode fazer no maximo? Se seu processo foi CPU bound, eh melhor ter X workers trabalhando em paralelo, onde X eh o numero de cores da sua CPU. Se seu processo for IO bound, voce deve ter uma thread somente gravando arquivos de forma sequencial se estiver usando HDD, e N threads caso esteja gravando em SSD. Se voce tiver 10 processos gravando em arquivos num HDD ao mesmo tempo, suas operacoes de disco vao demorar, pois o HDD na pratica soh vai escrever um por vez e tera de ficar mudando o ponteiro de escrita toda hora para escrever em varios arquivos ao mesmo tempo, tornando o processo muito mais lento que com uma soh thread.

Essas perguntas sao fundamentais, pois se nao tiver clara sua necessidade antes de comecar, voce podera piorar a performance ao inves de melhorar.

Pela explicacao que voce deu sobre o seu problema, seu processo eh quase 100% IO Bound, ele tem chamadas a APIs e escritas em arquivos, quase nao tem calculos ou processamentos.

Voce nao deixou claro se suas APIs oferecem chamadas assincronas (melhor no seu caso) e quantas requisicoes maximas sua API consegue receber em paralelo sem ter queda de performance. Pesquisar isso tambem eh importante, pois muda o numero de workers que voce pode ter fazer acesso a API.

Eu imagino seu problema resolvido da seguinte forma:

  • O processo A recebe cordenadas geograficas. Esse processo enfileira 12 mensagens com as coordenadas para o pool de processos B.
  • Aqui vale map/reduce. Voce mapeia as saidas do processo B para o processo C, enviando a mensagem para o processo C somente quando todas as 12 mensagens para aquela coordenada tiverem sido processadas. Existem varias formas de fazer isso, mas vou deixar para responder em perguntas futuras se voce tentar implementar.
  • O processo C faz a chamada opcional a API quando necessario. A saida eh encaminhada para o processo D.
  • O processo D grava em arquivo.

Para cada processo, voce controla quantas mensagens podem ser processadas em paralelo de acordo com o tipo de IO. Por exemplo:
  • O processo A recebe a entrada, entao ele deve ser non-blocking e deve simplesmente enfileirar mensagens e retornar o mais rapido possivel. Precisa ser o processo mais leve.
  • Os processos B e C fazem basicamente chamadas a API, entao deveriam usar um pool compartilhado cujo numero maximo de threads/processos eh o numero maximo de requisicoes simultaneas que a API suporta.
  • O processo D deve ter uma thread para HDD e mais threads para SSD. Veja http://codecapsule.com/2014/02/12/coding-for-ssds-part-5-access-patterns-and-system-optimizations/ para mais detalhes.


Abracos,
Marcelo.


---
Você recebeu essa mensagem porque está inscrito no grupo "Python Brasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para python-brasi...@googlegroups.com.

Para mais opções, acesse https://groups.google.com/d/optout.



<< ideas don't deserve respect >>

Eduardo Cuducos

unread,
Dec 7, 2016, 8:53:06 PM12/7/16
to python...@googlegroups.com
Galera, muito obrigado pelas respostas, dicas, sugestões, e tudo mais.

Tenho muito material para estudar e melhorar com as dicas de vocês. Sério, difícil eu responder à altura da ajuda que recebi por aqui. E me desculpe pela demora a retomar o tópico — passei por uma cirurgia semana passada, então tive que diminuir o ritmo aqui.

Vou responder ou comentar aqui alguns pontos que vi nas respostas de vocês (Nilo, muito obrigado pela atenção ao ler meu código, não tenho muito o que comentar, vou tentar arrumar com o teu code review, mas ainda não tive tempo!).

Resumindo: quando eu tentar reescrever o script com a ajuda que recebi aqui, atualizo vocês! Muito obrigado e grande abraço ; )

Sobre distribuir a tarefa em várias máquinas

Isso vai um pouco contra os preceitos de reprodutibilidade que muitos projetos de data science abraçam. Tudo bem ter um script que demore x dias para rodar, mas depender de uma infra já restringe muito a reprodutibilidade eu acho.

Sobre banco de dados ou arquivo de dataset como fonte de verdade

O projeto já começou, como muitos em data science, com datasets (arquivos) e assim devo continuar. Mesmo assim ideia de usar um banco de dados (Redis, Postgres…) como passo intermediário parece boa! Obrigado Avraham e Luciano ; )

Se seu processo é IO bound ou CPU bound. Ele passar mais tempo fazendo contas e usando CPU ou na maior parte do tempo ele faz IO?

Nem um, nem outro. Ele passa mais tempo esperando as respostas das requisições HTTP. Todo o resto é leve ; ) A API que recebe as requisições é robusta (Google Places) e, grosso modo, só me limita a 150k requisições/dia. Por isso, inclusive, tenho que salvar os resultados antes de terminar de rodar o script (pois só vou ter o dataset depois de 4 ou 5 dias rodando o script).

Quantas operacoes em paralelo voce pode fazer no maximo?

Isso tem que ser variável — dada a prioridade de reprodutibilidade, ele tem que rodar com 4 processos na minha máquina, 2 no servidor e 1 no Docker por exemplo.

Qual o tipo de analise está sendo feita?


flock e fcntl

Confesso que não conhecia esses dois — mais coisa para a lista de estudos! Obrigado Nilo e Francisco.

Ferramentas de big data

Não creio que, apesar do volume de requisições HTTP seja o caso de recorrer ao aparato de bug data. São 60mil empresas no dataset, não é muito…

gevent vs asyncio

Me convenci que o melhor vai ser reestruturar e usar asyncio de cabo a rabo!

Lua

O script é parte de um projeto maior. Usar outra linguagem que não Python (ou R0 vai ter o trabalho extra de incluir isso oficialmente no stack do projeto — prezando a reprodutibilidade, como já expliquei ; )

Pode passar o link para o PR em questão?

PR original juntamos em uma branch para que eu pudesse aprimorar o script. Ambos os links estão no email original. Qualquer contribuição pode mandar como PR para essa branch que está valendo! Ou se quiser, o PR work in progress é esse (mas como estou me recuperando da cirurgia não devo mexer nisso nos próximos dias).

Eu dei uma lida no projeto e vi que as notas fiscais são coisa de 1TB, é isso mesmo? Qual o formato do arquivo?

Não entendi direito tua pergunta. Temos um script que faz o download das notas ficais escaneadas. Se fizer de tudo (acho que ninguém fez), deve dar perto de 1 TB. A Câmara disponibiliza isso em PDF.

Se vocês tiverem alguns issues no projeto que estejam com dificuldades, posso tentar submeter umas PRs, se for ajudar.

Qualquer ajuda é bem vinda. Temos muitas issues, de vários assuntos (dev. data science, devops, etc.) nos nossos repositórios:
  • Serenata de Amor — exploração em data science
  • Rosie — core de machine learning
  • Jarbas — API (JSON e GUI)
  • Toolbox —ferramentas comuns à Rosie e ao repo Serenata de Amor
Hoje expliquei um pouco mais sobre essa arquitetura em um Hangouts coletivo. Quando temos muita dificuldade (técnica) normalmente recorro aqui às listas e grupos. Então por aqui vais ficar sabendo.




Marcelo Valle (BLOOMBERG/ LONDON)

unread,
Dec 8, 2016, 8:30:18 AM12/8/16
to python...@googlegroups.com
> Se seu processo é IO bound ou CPU bound. Ele passar mais tempo fazendo contas e usando CPU ou na maior parte do tempo ele faz IO?

> Nem um, nem outro. Ele passa mais tempo esperando as respostas das requisições HTTP. Todo o resto é leve ; ) A API que recebe as requisições é robusta (Google Places) e, grosso modo, só me limita a 150k requisições/dia. Por isso, inclusive, tenho que salvar os resultados antes de terminar de rodar o script (pois só vou ter o dataset depois de 4 ou 5 dias rodando o script).

Se ele passa a maior parte do tempo fazendo requisicoes http, ele eh IOBound. Acesso http eh acesso IO (rede)
O ideal eh usar muitas threads em paralelo, cada uma fazendo IO, e somente uma thread gera os requests para essas requisicoes.
De fato, parece ser o caso para async IO

Subject: Re: [python-brasil] Paralelismo, concorrência e escrita em arquivo
Galera, muito obrigado pelas respostas, dicas, sugestões, e tudo mais.
--
--
------------------------------------
Grupo Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar
 
<*> Para visitar o site do grupo na web, acesse:
http://groups.google.com/group/python-brasil
 
<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@googlegroups.com

---
Você recebeu essa mensagem porque está inscrito no grupo "Python Brasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para python-brasi...@googlegroups.com.
Para mais opções, acesse https://groups.google.com/d/optout.

Cleiton Bueno

unread,
Dec 8, 2016, 9:05:25 AM12/8/16
to Python Brasil
@Cuducos não conhecia e achei sensacional a ideia e o projeto, não tenho know-how como a maioria, meu foco é python mais para mundo Linux Embedded e IO's em geral.

Mas irei compartilhar a ideia ;)

Att,
Cleiton Bueno


Eduardo Cuducos

unread,
Dec 8, 2016, 9:46:39 AM12/8/16
to python...@googlegroups.com
Opa, valeu pela aula, Marcelo! Captei agora o sentido de IO, eu estava mais limitado a pensar em escrita de arquivo — desculpe a ignorância. E muito obrigado ; )

Cleiton, muito obrigado pelo apoio também!

Eduardo Cuducos

unread,
Mar 11, 2017, 11:41:34 AM3/11/17
to python...@googlegroups.com
Queridos, muito obrigado mais uma vez pela ajuda!

Meses depois consegui voltar a esse script! Com muita ajuda da Jessica Temporal, conhecida por aqui, eis o resultado, caso alguém se interesse:


Os pontos principais foram usar:

* aiohttp para fazer as requisições em paralelo 
* aiofiles para gerenciar as escritas em arquivo em _paralello_ (assíncronas, na verdade…)
* asyncio.Semaphore para criar um limite máximo de requisições abertas de forma assíncrona

🍾 Ufa!
--
Eduardo Cuducos

Marcelo Valle (BLOOMBERG/ LONDON)

unread,
Mar 13, 2017, 8:07:44 AM3/13/17
to python...@googlegroups.com
Eduardo, 

O projeto serenata de amor tem uma lista de discussao a qual eu possa me inscrever? Ou soh o grupo do telegram?

Mas algumas partes dele estao dificeis de entender, seria interessante poder perguntar quando surgirem duvidas.

-Marcelo.

Eduardo Cuducos

unread,
Mar 13, 2017, 8:18:57 AM3/13/17
to python...@googlegroups.com
Oi Marcelo,

> O projeto serenata de amor tem uma lista de discussao
> a qual eu possa me inscrever? Ou soh o grupo do
> telegram?

Galera moderninha: só Telegram mesmo hahaha… Quando a discussão tem um tópico encorpado ela vai para Issue ou PR no GitHub ; )

> Eu achei esse documento:
> Mas algumas partes dele estao dificeis de entender, seria
> interessante poder perguntar quando surgirem duvidas.

Se tu puder criar uma Issue seria ótimo. É bom ver onde estamos derrapando — inclusive já sabemos que esse documento está grande demais, mas ainda não foi prioridade 1) reestrutura-lo ou 2) pensar numa nova “plataforma” para essas informações (quebrar em vários .md? usar wiki? GitBook? Etc…).

Muito obrigado,

Cuducos

Charles tenorio

unread,
Mar 13, 2017, 8:33:33 AM3/13/17
to Python Brasil
Olá sei que não tem muito haver com python, mas eu utilizo Golang, pra programação concorrente, muito simples de se fazer caso precise de um dev pra esse parte de concorrência estou a disposição. Eu também trabalho com python com flask. 
Reply all
Reply to author
Forward
0 new messages