Nltk: многопроцессорность и nltk не работают вместе

Созданный на 16 апр. 2015  ·  22Комментарии  ·  Источник: nltk/nltk

Честно говоря, это не столько серьезный вопрос, сколько любопытный. Я обнаружил, что когда NLTK импортируется, это приведет к преждевременному завершению любого подпроцесса Python при сетевом вызове. Пример кода:

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)

Запустите его с импортированным NLTK, и вы увидите, что вызов urlopen () никогда не выполняется. Закомментируйте строку import nltk , и она будет выполнена нормально.

Зачем?

* изменить: это для Python 2. Я еще не тестировал его на 3.

admin bug inactive multithread / multiprocessing pythonic

Самый полезный комментарий

Я не очень хорошо знаком с nltk, но я немного покопался, чтобы увидеть, что заставило тест пройти / не пройти. Вот что мне нужно было сделать с пакетом __init__.py , чтобы пройти тест:


Подробности (нажмите, чтобы развернуть)

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


Интересно, что весь отключенный импорт в конечном итоге приводит к импорту tkinter , что, как я думаю, является основной причиной. Если я заменю import nltk на import tkinter в тестовом скрипте, я получу очень похожий отчет о сбое, оба ссылаются на tkinter.

Насколько я могу судить, эти пакеты напрямую импортируют tkinter :

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

Из приведенных выше изменений в основном пакете __init__ , это проблемный импорт и то, как они прослеживаются до импорта 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 )

Все 22 Комментарий

Есть ли исключения?

нет. Я поместил предложение try .. except: вокруг import urllib2; print... но ничего от него не получил.

Я столкнулся с той же проблемой. Я только что открыл вопрос SO, который может быть полезен для ссылки здесь: http://stackoverflow.com/questions/30766419/python-child-process-silently-crashes-when-issuing-an-http-request

Дочерний процесс действительно тихо падает без дополнительного уведомления.

Я не согласен с вами @ oxymor0n ,

The child process is indeed crashing silently without further notice.

Мы также сталкиваемся с этой проблемой с комбинацией: nltk, gunicorn (с nltk, загруженным через prefork) и flask.

Удалите импорт nltk, и все работает. Кроме nltk.

/ cc @escherba

@ninowalker , @ oxymor0n Странно, мои процессы отлично работают с кодом, получаю:

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

Это ожидаемый результат, верно?

Это тоже не нарушает мою просьбу:

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

Я использую:

  • Python 2.7.6
  • nltk 3.0.3
  • убунту 14.04

Я столкнулся с той же проблемой, что и @Hiestaa . У меня есть вспомогательный файл string_util.python, который импортирует nltk, но он не используется в основном файле python, который использует модуль многопроцессорности для запуска многопроцессорного поискового робота. Симптомом является то, что дочерний процесс просто застревает и нет сообщения об ошибке (даже сообщения об исключении).
После комментирования импорта и функций, связанных с nltk, проблема была решена.

Подробности:
ОС: Yosemite 10.10.5
Python: 2.7.10
Получение содержимого страницы: сначала я использовал urllib2, а потом переключился на запросы.

Это очень серьезная ошибка, и я надеюсь, что кто-нибудь сможет ее исправить. Спасибо!

Я думаю, что это серьезная проблема, если вы занимаетесь НЛП производственного уровня. Мы используем воркеры Rq (http://python-rq.org/) для запуска нескольких конвейеров NLP, которые незаметно убиваются при выполнении сетевых вызовов. Надеюсь, скоро все исправят. Спасибо!

@sasinda : Вы можете позвонить в список рассылки nltk-dev, чтобы узнать, сможете ли вы привлечь внимание к этой проблеме.

@sasinda Я не уверен, как именно работает Rq, но в моем проекте NLP производственного уровня мне удалось обойти эту проблему, запустив каждый процесс в отдельном и изолированном интерпретаторе Python, используя сценарий оболочки для их создания при запуске. В этом случае python никогда не должен форкнуть, и тихий сбой из nltk никогда не происходит. Может, пока это поможет.

Я обнаружил, что выполнение импорта на уровне функций позволяет избежать этой проблемы.

Другими словами, это работает:

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

а это не так:

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

Спасибо @mpenkov. Решает ли это проблему?

@stevenbird Я так не думаю. Это обходной путь, но не исправление.

ИМХО, если импорт сторонней библиотеки ломает компонент стандартной библиотеки Python, где-то происходит что-то нечестивое, и его необходимо исправить.

@mpenkov Я не совсем уверен, почему это работает, но вот еще одно решение, которое я нашел, работает. Похоже, что создание открывателя в родительском процессе исправляет это. Изменение исходного кода @ 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 Вы все еще сталкиваетесь с одной и той же проблемой?

Я не смог воспроизвести проблему на своей машине:

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)

дает мне:

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

Я на:

  • Python 2.7.12
  • НЛТК 3.2.5
  • Ubuntu 16.04.3

@alvations Я давно не обнаружил эту проблему.
Я даже забыл, в какой базе проекта возникла эта проблема, поэтому я не мог сказать вам, есть ли у меня проблема или нет.
Сожалею!

@alvations Я тоже не помню, какие из моих проектов страдали именно от этой проблемы.

Я запустил ваш код на своей машине и не смог воспроизвести проблему.

Python 2.7.12
nltk 3.2.1
macOS 10.12.6

@alvations Я тоже больше не работаю над этим проектом. Но использовал один из этих обходных путей.
Я пробовал ваш код, но все же дочерний процесс для меня завершился с ошибкой сегмента (код выхода 11) (выходит на строке: urllib2.urlopen ("https://www.google.com") .read () [: 100])

Однако он работал с 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. | (по умолчанию, 20 декабря 2016 г., 23:05:08)
    [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] на darwin

Насколько я могу судить, эта проблема, похоже, затрагивает macOS. Пока использовал Python 3.6,

  • macOS 10.13 (не работает)
  • Centos 7.2 (успешно)
  • Ubuntu 16.04 (успешно)

Измененный скрипт OP для 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)

Вывод:

Fetch URL
Child process returned

Подпроцесс неожиданно завершает работу, получая вывод, аналогичный тому, что мы видели в этой публикации о переполнении стека .

Я думаю, что это ошеломляет. Это может иметь какое-то отношение к обработке потоков в MacOS.

Я не очень хорошо знаком с nltk, но я немного покопался, чтобы увидеть, что заставило тест пройти / не пройти. Вот что мне нужно было сделать с пакетом __init__.py , чтобы пройти тест:


Подробности (нажмите, чтобы развернуть)

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


Интересно, что весь отключенный импорт в конечном итоге приводит к импорту tkinter , что, как я думаю, является основной причиной. Если я заменю import nltk на import tkinter в тестовом скрипте, я получу очень похожий отчет о сбое, оба ссылаются на tkinter.

Насколько я могу судить, эти пакеты напрямую импортируют tkinter :

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

Из приведенных выше изменений в основном пакете __init__ , это проблемный импорт и то, как они прослеживаются до импорта 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 )

Спасибо @rpkilby , это очень полезно!

Похоже, эта проблема https://stackoverflow.com/questions/16745507/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-freezing

Я думаю, что тинктер уже довольно давно является для нас проблемой. Возможно, будет хорошо, если мы найдем ему альтернативу.

Я согласен. Более краткосрочным решением было бы похоронить импорт tkinter внутри классов и методов, которым требуется tkinter, и избежать его импорта программами, которым он не нужен. Мы уже сделали нечто подобное для numpy.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги