Honestamente, esse assunto não é tão sério quanto é curioso. Descobri que, quando o NLTK é importado, fará com que qualquer subprocesso Python termine prematuramente em uma chamada de rede. Código de exemplo:
from multiprocessing import Process
import nltk
import time
def child_fn():
print "Fetch URL"
import urllib2
print urllib2.urlopen("https://www.google.com").read()[:100]
print "Done"
while True:
child_process = Process(target=child_fn)
child_process.start()
child_process.join()
print "Child process returned"
time.sleep(1)
Execute-o com o NLTK importado e você verá que a chamada urlopen () nunca é executada. Comente a linha import nltk
e ela será executada corretamente.
Por quê?
* editar: isso é para Python 2. Eu não testei no 3 ainda.
Você consegue alguma exceção?
não. coloquei uma cláusula try .. except:
torno de import urllib2; print...
mas não obtive nada dela.
Estou tendo exatamente o mesmo problema. Acabei de abrir uma pergunta do SO que pode ser útil para um link aqui: http://stackoverflow.com/questions/30766419/python-child-process-silently-crashes-when-issuing-an-http-request
O processo filho está de fato travando silenciosamente sem aviso prévio.
Eu discordo de você @ oxymor0n , isso me parece um problema muito sério. Isso basicamente significa que sempre que nltk é importado, não há como emitir uma solicitação de um processo filho, o que pode ser realmente irritante ao trabalhar com APIs.
The child process is indeed crashing silently without further notice.
Também estamos enfrentando esse problema com a combinação de: nltk, gunicorn (com nltk carregado via prefork) e flask.
Remova a importação nltk e tudo funcionará. Exceto nltk.
/ cc @escherba
@ninowalker , @ oxymor0n É estranho, meus processos funcionam bem com o código, eu entendo:
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="de"><head><meta content
Done
Child process returned
Essa é a saída esperada, certo?
Isso também não interrompe meu pedido:
alvas<strong i="13">@ubi</strong>:~$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from multiprocessing import Process
>>> import requests
>>> from pprint import pprint
>>> Process(target=lambda: pprint(
... requests.get('https://api.github.com'))).start()
>>> <Response [200]>
>>> import nltk
>>> Process(target=lambda: pprint(
... requests.get('https://api.github.com'))).start()
>>> <Response [200]>
Estou a usar:
Encontrei o mesmo problema que o @Hiestaa teve. Tenho o arquivo auxiliar string_util.python que importa nltk, mas não é usado no arquivo python principal que usa o módulo de multiprocessamento para iniciar um rastreador de multiprocessos. O sintoma é que o processo filho simplesmente fica travado e não há mensagem de erro (nem mesmo mensagem de exceção).
Depois de comentar as importações e funções relacionadas ao nltk, o problema foi resolvido.
Detalhes:
OS: Yosemite 10.10.5
Python: 2.7.10
Recuperar o conteúdo da página: usei o urllib2 inicialmente, depois mudei para as solicitações.
Este é um bug muito sério e espero que alguém possa intervir e corrigi-lo. Obrigado!
Eu acho que este é um problema sério se você está fazendo PNL em nível de produção. Estamos usando workers Rq (http://python-rq.org/), para executar vários pipelines de PNL, que são silenciados silenciosamente ao fazer chamadas de rede. Espero que haja uma correção em breve. Obrigado!
@sasinda : Você pode querer fazer uma chamada na lista de e-mail nltk-dev para ver se consegue obter alguma atenção para este problema.
@sasinda Não tenho certeza de como o Rq funciona exatamente, mas no meu projeto de PNL de nível de produção, consegui contornar esse problema iniciando cada processo em um interpretador python separado e isolado, usando um script de shell para gerá-los na inicialização. Neste caso, o python nunca precisa se ramificar e a falha silenciosa do nltk nunca acontece. Talvez isso possa ajudar nesse meio tempo.
Descobri que executar a importação no nível da função evita o problema.
Em outras palavras, isso funciona:
def split(words):
import nltk
return nltk.word_tokenize(words)
e isso não:
import nltk
def split(words):
return nltk.word_tokenize(words)
Obrigado @mpenkov. Isso resolve o problema?
@stevenbird Acho que não. É uma solução alternativa, mas não é uma solução.
IMHO, se importar uma biblioteca de terceiros quebrar um componente de biblioteca padrão do Python, algo profano está acontecendo em algum lugar e precisa ser consertado.
@mpenkov Não tenho certeza de por que isso funciona, mas aqui está outra solução alternativa que descobri que funciona. Construir um abridor no processo pai parece consertá-lo. Modificando o código original de @ oxymor0n :
from multiprocessing import Process
import nltk
import time
import urllib2
# HACK
urllib2.build_opener(urllib2.HTTPHandler())
def child_fn():
print "Fetch URL"
import urllib2
print urllib2.urlopen("https://www.google.com").read()[:100]
print "Done"
while True:
child_process = Process(target=child_fn)
child_process.start()
child_process.join()
print "Child process returned"
time.sleep(1)
@mpenkov @ninowalker , @ oxymor0n @sasinda @wenbowang Todos vocês ainda enfrentam o mesmo problema?
Não consegui replicar o problema na minha máquina:
from multiprocessing import Process
import nltk
import time
def child_fn():
print "Fetch URL"
import urllib2
print urllib2.urlopen("https://www.google.com").read()[:100]
print "Done"
while True:
child_process = Process(target=child_fn)
child_process.start()
child_process.join()
print "Child process returned"
time.sleep(1)
me dá:
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-SG"><head><meta cont
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-SG"><head><meta cont
Done
Child process returned
Fetch URL
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-SG"><head><meta cont
Done
Estou dentro:
@alvations Já se passou muito tempo desde que descobri esse problema.
Até esqueci qual base de projeto estava tendo esse problema, então não posso dizer se ainda tenho o problema ou não.
Desculpe!
@alvations Eu também não me lembro qual dos meus projetos sofreu com esses problemas específicos.
Executei seu código na minha máquina e não consegui replicar o problema.
Python 2.7.12
nltk 3.2.1
macOS 10.12.6
@alvations Eu também não estou mais trabalhando nesse projeto. Mas usou uma dessas soluções alternativas.
Tentei seu código, mas ainda assim o processo filho sai com falha de segmento (código de saída 11) para mim (sai na linha: urllib2.urlopen ("https://www.google.com") .read () [: 100])
No entanto, funcionou com urllib3 (https://urllib3.readthedocs.io/en/latest/).
Até onde eu sei, esse problema parece afetar o macOS. Usando Python 3.6 até agora,
Script do OP modificado para python3:
from multiprocessing import Process
import nltk
import time
def child_fn():
from urllib.request import urlopen
print("Fetch URL")
print(urlopen("https://www.google.com").read()[:100])
print("Done")
child_process = Process(target=child_fn)
child_process.start()
child_process.join()
print("Child process returned")
time.sleep(1)
Resultado:
Fetch URL
Child process returned
O subprocesso fecha inesperadamente, recebendo uma saída semelhante ao que é visto nesta postagem do Stack Overflow .
Eu acho que isso é incompreensível. Pode ter algo a ver com o tratamento de threads no MacOS.
Não estou muito familiarizado com o nltk, mas dei uma espiada às cegas para ver o que fez o teste passar / falhar. Aqui está o que eu tive que fazer com o pacote __init__.py
para passar no teste:
Detalhes (clique para expandir)
###########################################################
# TOP-LEVEL MODULES
###########################################################
# Import top-level functionality into top-level namespace
from nltk.collocations import *
from nltk.decorators import decorator, memoize
# from nltk.featstruct import *
# from nltk.grammar import *
from nltk.probability import *
from nltk.text import *
# from nltk.tree import *
from nltk.util import *
from nltk.jsontags import *
# ###########################################################
# # PACKAGES
# ###########################################################
# from nltk.chunk import *
# from nltk.classify import *
# from nltk.inference import *
from nltk.metrics import *
# from nltk.parse import *
# from nltk.tag import *
from nltk.tokenize import *
from nltk.translate import *
# from nltk.sem import *
# from nltk.stem import *
# Packages which can be lazily imported
# (a) we don't import *
# (b) they're slow to import or have run-time dependencies
# that can safely fail at run time
from nltk import lazyimport
app = lazyimport.LazyModule('nltk.app', locals(), globals())
chat = lazyimport.LazyModule('nltk.chat', locals(), globals())
corpus = lazyimport.LazyModule('nltk.corpus', locals(), globals())
draw = lazyimport.LazyModule('nltk.draw', locals(), globals())
toolbox = lazyimport.LazyModule('nltk.toolbox', locals(), globals())
# Optional loading
try:
import numpy
except ImportError:
pass
else:
from nltk import cluster
# from nltk.downloader import download, download_shell
# try:
# from six.moves import tkinter
# except ImportError:
# pass
# else:
# try:
# from nltk.downloader import download_gui
# except RuntimeError as e:
# import warnings
# warnings.warn("Corpus downloader GUI not loaded "
# "(RuntimeError during import: %s)" % str(e))
# explicitly import all top-level modules (ensuring
# they override the same names inadvertently imported
# from a subpackage)
# from nltk import ccg, chunk, classify, collocations
# from nltk import data, featstruct, grammar, help, inference, metrics
# from nltk import misc, parse, probability, sem, stem, wsd
# from nltk import tag, tbl, text, tokenize, translate, tree, treetransforms, util
Curiosamente, todas as importações desativadas acabam levando de volta à importação de tkinter
, que eu acho que é a causa raiz. Se eu substituir import nltk
por import tkinter
no script de teste, obtenho um relatório de falha muito semelhante, ambos fazendo referência ao tkinter.
Pelo que eu posso dizer, esses pacotes importam diretamente tkinter
:
nltk.app
nltk.draw
nltk.sem
Das mudanças acima para o pacote principal __init__
, essas são as importações problemáticas e como elas remontam à importação do tkinter
nltk.featstruct
( sem
)nltk.grammar
( featstruct
)nltk.tree
( grammar
)nltk.chunk
( chunk.named_entity
> tree
)nltk.parse
( parse.bllip
> tree
)nltk.tag
( tag.stanford
> parse
)nltk.classify
( classify.senna
> tag
)nltk.inference
( inference.discourse
> sem
, tag
)nltk.stem
( stem.snowball
> corpus
> corpus.reader.timit
> tree
)Obrigado @rpkilby , isso é muito útil!
Parece que este problema https://stackoverflow.com/questions/16745507/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-freezing
Eu acho que mexer tem sido um problema para nós há algum tempo. Talvez seja bom se encontrarmos uma alternativa para isso.
Concordo. Uma solução de curto prazo seria enterrar as importações do tkinter dentro das classes e métodos que precisam do tkinter e evitar importá-lo por programas que não precisam dele. Já fizemos algo semelhante para o numpy.
Comentários muito úteis
Não estou muito familiarizado com o nltk, mas dei uma espiada às cegas para ver o que fez o teste passar / falhar. Aqui está o que eu tive que fazer com o pacote
__init__.py
para passar no teste:Detalhes (clique para expandir)
Curiosamente, todas as importações desativadas acabam levando de volta à importação de
tkinter
, que eu acho que é a causa raiz. Se eu substituirimport nltk
porimport tkinter
no script de teste, obtenho um relatório de falha muito semelhante, ambos fazendo referência ao tkinter.Pelo que eu posso dizer, esses pacotes importam diretamente
tkinter
:nltk.app
nltk.draw
nltk.sem
Das mudanças acima para o pacote principal
__init__
, essas são as importações problemáticas e como elas remontam à importação do tkinternltk.featstruct
(sem
)nltk.grammar
(featstruct
)nltk.tree
(grammar
)nltk.chunk
(chunk.named_entity
>tree
)nltk.parse
(parse.bllip
>tree
)nltk.tag
(tag.stanford
>parse
)nltk.classify
(classify.senna
>tag
)nltk.inference
(inference.discourse
>sem
,tag
)nltk.stem
(stem.snowball
>corpus
>corpus.reader.timit
>tree
)