Nltk: Multiprocessing und Nltk spielen nicht gut zusammen

Erstellt am 16. Apr. 2015  ·  22Kommentare  ·  Quelle: nltk/nltk

Ehrlich gesagt ist dieses Problem nicht so ernst wie neugierig. Ich habe festgestellt, dass beim Importieren von NLTK jeder Python-Unterprozess bei einem Netzwerkaufruf vorzeitig beendet wird. Beispielcode:

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)

Führen Sie es mit importiertem NLTK aus, und Sie werden sehen, dass der Aufruf von urlopen () nie ausgeführt wird. Kommentieren Sie die Zeile import nltk aus, und sie wird einwandfrei ausgeführt.

Warum?

* edit: Dies ist für Python 2. Ich habe es noch nicht auf 3 getestet.

admin bug inactive multithread / multiprocessing pythonic

Hilfreichster Kommentar

Ich bin mit nltk nicht besonders vertraut, aber ich habe ein wenig blind herumgestochert, um zu sehen, warum der Test bestanden / nicht bestanden wurde. Folgendes musste ich mit dem Paket __init__.py tun, um den Test zu bestehen:


Details (zum Vergrößern anklicken)

###########################################################
# 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


Interessanterweise führen alle deaktivierten Importe letztendlich zum Import von tkinter , was meiner Meinung nach die Hauptursache ist. Wenn ich im Testskript import nltk durch import tkinter ersetze, erhalte ich einen sehr ähnlichen Absturzbericht, der beide auf tkinter verweist.

Soweit ich weiß, importieren diese Pakete direkt tkinter :

  • nltk.app
  • nltk.draw
  • nltk.sem

Von den obigen Änderungen am Hauptpaket __init__ sind dies die problematischen Importe und wie sie auf den Import von tkinter zurückgehen

  • 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 )

Alle 22 Kommentare

Bekommst du irgendwelche Ausnahmen?

Nein. Ich habe eine try .. except: -Klausel um die import urllib2; print... aber nichts davon bekommen.

Ich habe genau das gleiche Problem. Ich habe gerade eine SO-Frage geöffnet, die nützlich sein kann, um hier verlinkt zu werden: http://stackoverflow.com/questions/30766419/python-child-process-silently-crashes-when-issuing-an-http-request

Der untergeordnete Prozess stürzt tatsächlich ohne weitere Ankündigung lautlos ab.

Ich bin nicht einverstanden mit Ihnen @ oxymor0n , dies scheint mir ein ziemlich ernstes Problem zu sein. Dies bedeutet im Grunde, dass es bei jedem Import von nltk keine Möglichkeit gibt, eine Anforderung von einem untergeordneten Prozess auszugeben, was bei der Arbeit mit APIs sehr ärgerlich sein kann.

The child process is indeed crashing silently without further notice.

Dieses Problem tritt auch bei der Kombination aus: nltk, Gunicorn (mit nltk über die Vorgabel geladen) und Kolben auf.

Entfernen Sie den nltk-Import, und alles funktioniert. Außer nltk.

/ cc @escherba

@ninowalker , @ oxymor0n Es ist seltsam, meine Prozesse laufen gut mit dem Code, ich bekomme:

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

Das ist die erwartete Leistung, oder?

Es bricht meine Bitte auch damit nicht:

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]>

Ich benutze:

  • Python 2.7.6
  • nltk 3.0.3
  • Ubuntu 14.04

Ich hatte das gleiche Problem wie @Hiestaa . Ich habe die Hilfsdatei string_util.python, die nltk importiert, aber sie wird nicht in der Hauptpython-Datei verwendet, die das Multiprocessing-Modul verwendet, um einen Multi-Prozess-Crawler zu starten. Das Symptom ist, dass der untergeordnete Prozess einfach hängen bleibt und es keine Fehlermeldung gibt (nicht einmal eine Ausnahmemeldung).
Nach dem Auskommentieren von nltk-bezogenen Importen und Funktionen wurde das Problem behoben.

Einzelheiten:
Betriebssystem: Yosemite 10.10.5
Python: 2.7.10
Seiteninhalt abrufen: Ich habe zunächst urllib2 verwendet und später zu Anforderungen gewechselt.

Dies ist ein sehr schwerwiegender Fehler, und ich hoffe, dass jemand eingreifen und ihn beheben kann. Vielen Dank!

Ich denke, dies ist ein ernstes Problem, wenn Sie NLP auf Produktionsebene durchführen. Wir verwenden Rq-Mitarbeiter (http://python-rq.org/), um mehrere NLP-Pipelines auszuführen, die bei Netzwerkanrufen stillschweigend beendet werden. Hoffe, es wird bald eine Lösung geben. Vielen Dank!

@sasinda : Vielleicht

@sasinda Ich bin mir nicht sicher, wie Rq genau funktioniert, aber in meinem NLP-Projekt auf Produktionsebene konnte ich dieses Problem umgehen,

Ich habe festgestellt, dass das Durchführen des Imports auf Funktionsebene das Problem vermeidet.

Mit anderen Worten, das funktioniert:

def split(words):
    import nltk
    return nltk.word_tokenize(words)

und das nicht:

import nltk
def split(words):
    return nltk.word_tokenize(words)

Danke @mpenkov. Behebt dies das Problem?

@stevenbird Ich glaube nicht. Es ist eine Problemumgehung, aber keine Lösung.

IMHO, wenn beim Importieren einer Bibliothek eines Drittanbieters eine Python-Standardbibliothekskomponente beschädigt wird, passiert irgendwo etwas Unheiliges und muss behoben werden.

@mpenkov Ich bin mir nicht ganz sicher, warum dies funktioniert, aber hier ist eine weitere Problemumgehung, die ich gefunden habe. Das Erstellen eines Openers im übergeordneten Prozess scheint das Problem zu beheben. Ändern des Originalcodes von @ 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 Stehen Sie alle immer noch vor dem gleichen Problem?

Ich konnte das Problem auf meinem Computer nicht replizieren:

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)

gibt mir:

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

Ich bin auf:

  • Python 2.7.12
  • NLTK 3.2.5
  • Ubuntu 16.04.3

@alvations Es ist lange her, dass ich dieses Problem gefunden habe.
Ich habe sogar vergessen, bei welcher Projektbasis dieses Problem aufgetreten ist, daher konnte ich Ihnen nicht sagen, ob ich das Problem noch habe oder nicht.
Es tut uns leid!

@alvations Auch ich kann mich nicht erinnern, welches meiner Projekte unter diesen spezifischen Problemen gelitten hat.

Ich habe Ihren Code auf meinem Computer ausgeführt und konnte das Problem nicht replizieren.

Python 2.7.12
nltk 3.2.1
macOS 10.12.6

@alvations Auch ich arbeite nicht mehr an diesem Projekt. Aber verwendet eine dieser Problemumgehungen.
Ich habe Ihren Code ausprobiert, aber der untergeordnete Prozess wird für mich immer noch mit einem Segmentfehler (Exit-Code 11) beendet (wird in Zeile: urllib2.urlopen ("https://www.google.com") beendet .read () [: 100])

Es funktionierte jedoch mit urllib3 (https://urllib3.readthedocs.io/en/latest/).

  • nltk (3.2.5)
  • urllib3 (1,22)
  • Mac OSX 10.12.16
  • Python 2.7.13 | Continuum Analytics, Inc. | (Standard, 20. Dezember 2016, 23:05:08)
    [GCC 4.2.1 Kompatibles Apple LLVM 6.0 (clang-600.0.57)] auf Darwin

Soweit ich das beurteilen kann, scheint dieses Problem macOS zu betreffen. Bisherige Verwendung von Python 3.6

  • macOS 10.13 (schlägt fehl)
  • Centos 7.2 (erfolgreich)
  • Ubuntu 16.04 (erfolgreich)

Geändertes OP-Skript für 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)

Ausgabe:

Fetch URL
Child process returned

Der Unterprozess wird unerwartet beendet und erhält eine ähnliche Ausgabe wie in diesem Beitrag zum Stapelüberlauf .

Ich denke, das ist ziemlich umwerfend. Dies hat möglicherweise etwas mit der Thread-Behandlung unter MacOS zu tun.

Ich bin mit nltk nicht besonders vertraut, aber ich habe ein wenig blind herumgestochert, um zu sehen, warum der Test bestanden / nicht bestanden wurde. Folgendes musste ich mit dem Paket __init__.py tun, um den Test zu bestehen:


Details (zum Vergrößern anklicken)

###########################################################
# 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


Interessanterweise führen alle deaktivierten Importe letztendlich zum Import von tkinter , was meiner Meinung nach die Hauptursache ist. Wenn ich im Testskript import nltk durch import tkinter ersetze, erhalte ich einen sehr ähnlichen Absturzbericht, der beide auf tkinter verweist.

Soweit ich weiß, importieren diese Pakete direkt tkinter :

  • nltk.app
  • nltk.draw
  • nltk.sem

Von den obigen Änderungen am Hauptpaket __init__ sind dies die problematischen Importe und wie sie auf den Import von tkinter zurückgehen

  • 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 )

Danke @rpkilby , das ist sehr hilfreich!

Es sieht so aus, als ob dieses Problem https://stackoverflow.com/questions/16745507/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-freezing ist

Ich denke, Basteln ist für uns schon seit einiger Zeit ein Schmerzpunkt. Vielleicht ist es gut, wenn wir eine Alternative dazu finden können.

Genau. Eine kurzfristigere Lösung wäre, die tkinter-Importe in den Klassen und Methoden zu vergraben, die tkinter benötigen, und zu vermeiden, dass sie von Programmen importiert werden, die sie nicht benötigen. Ähnliches haben wir schon für Numpy gemacht.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen