2009-08-04 5 views
5

Каков рекомендуемый способ прервать неожиданно длинные потоки в python? Я не могу использовать SIGALRM, так какЗавершить длинные потоки python

Некоторые уход должны быть приняты, если оба сигналы и нити используются в одной и той же программы . Фундаментальное значение для при использовании сигналов и потоков одновременно: всегда выполняет сигнал() в основной строке исполнения. Любая нить может выполнять alarm(), getsignal(), pause(), setitimer() или getitimer(); только основной поток может установить новый обработчик сигнала , и основной поток будет только один, чтобы принимать сигналы (это обеспечивается модулем Python сигнала , даже если реализация потока поддерживает отправку сигналы к отдельным потокам). Это значение означает, что сигналы не могут использоваться как средства связи между потоками . Вместо этого следует использовать блокировки.

Обновление: каждый поток в моем случае блокирует - он загружает веб-страницу с использованием модуля urllib2, а иногда операция занимает слишком много времени на чрезвычайно медленных сайтах. Вот почему я хочу прекратить такие медленные потоки

ответ

6

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

Для конкретного случая OP (задача потоков заключается в загрузке веб-страниц, а некоторые потоки блокируются навсегда из-за неправильной работы сайтов), идеальным решением является twisted - как это обычно делается для сетевых задач. В других случаях multiprocessing может быть лучше.

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

1

Если вы пытаетесь убить поток, код которого вы не контролируете, зависит от того, существует ли поток в блокирующем вызове или нет. По моему опыту, если поток правильно блокируется, нет рекомендуемого и переносимого способа сделать это.

Я столкнулся с этим при попытке работать с кодом в стандартной библиотеке (multiprocessing.manager Я смотрю на вас) с петлями, закодированными без условия выхода: приятно!

Существует несколько взаимосвязанных реализаций потоков (see here for an example), но тогда, если вы сами управляете потоковым кодом, вы должны иметь возможность записывать их таким образом, чтобы вы могли перехватывать их с помощью переменной условия какая-то.

1

Используйте объекты синхронизации и попросите поток завершить работу. В принципе, напишите об этом.

Если вы начинаете вытягивать нить под интерпретатором python, могут возникать всевозможные нечетные вещи, и это не только на Python, но и в большинстве случаев выполнения этой проблемы.

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

+0

Проблема заключается в том, что у вас есть один метод, который занимает слишком много времени (например, urllib.read(), который в некоторых случаях игнорирует таймауты), которые вы «Я хотел бы прервать. – kolinko

+1

Если вы выполняете это, прочитав в своем потоке, не можете ли вы просто перестать его ждать? В конце концов, он завершит/завершит неудачу/закончен, а затем он просто умрет? –

5

Как предложил Алекс Мартелли, вы можете использовать модуль многопроцессорности. Он очень похож на модуль Threading, так что вы должны легко начать работу. Ваш код может быть таким, например:

import multiprocessing 

def get_page(*args, **kwargs): 
    # your web page downloading code goes here 

def start_get_page(timeout, *args, **kwargs): 
    p = multiprocessing.Process(target=get_page, args=args, kwargs=kwargs) 
    p.start() 
    p.join(timeout) 
    if p.is_alive(): 
     # stop the downloading 'thread' 
     p.terminate() 
     # and then do any post-error processing here 

if __name__ == "__main__": 
    start_get_page(timeout, *args, **kwargs) 

Конечно, вам нужно как-то получить возвращаемые значения кода загрузки страницы. Для этого вы можете использовать multiprocessing.Pipe или multiprocessing.Queue (или другие способы, доступные при многопроцессорной обработке). Там есть дополнительная информация, а также образцы, которые вы можете проверить по телефону http://docs.python.org/library/multiprocessing.html.

И наконец, модуль многопроцессорности включен в python 2.6. Она также доступна для Python 2.5 и 2.4 в PyPI (вы можете использовать

easy_install многопроцессорных

)

или просто посетить PyPi и загрузить и установить пакеты вручную.

Примечание: Я понимаю, что это было опубликовано некоторое время назад. У меня была схожая проблема с этим и споткнулся здесь и увидел предложение Алекс Мартелли. Если бы он реализовал мою проблему и решил поделиться ею. (Я хотел бы поблагодарить Алекса за то, что он указал мне в правильном направлении.)

+0

У меня точно такая же проблема, но Процессы не выполняют трюк - они занимают слишком много памяти и одновременно работают 100 процессов и 4 ГБ оперативной памяти. Я сталкиваюсь с трудностями. – kolinko

Смежные вопросы