LINUX.ORG.RU

Python. Завершить поток (threading или thread).


0

1

Как корректно завершить поток? (thread или threading)
http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-i...
http://www.velocityreviews.com/forums/t330554-kill-a-thread-in-python.html
- не помогли ...

Можно ли обойтись без платформо-зависимых решений (pthread_kill, TerminateThread)?

★★★★★

Корректные завершение потока(по определению) - конец выполнения функции.
Завершение потока из-за эксепшна(как в примерах по ссылкам) - некорректное завершение потока.
Просто нужно это понять.
Если у тебя live-loop в теле функции потока, то корректным выходом будет использование while self.is_alive: .. . Сам флаг задавай через аксессор, в котором будет использоваться мьютекс.

Есть и ситуация, когда поток в теле не имеет самого цикла и тебе нужно завершать поток _некорректно_. В этом случае трудно сказать что лучше.

tia
()
Ответ на: комментарий от baverman

Вот схема программы:

from threading import Thread

# Потомок threading.Thread, выполнение которого
# можно завершать извне (Hacked).
class KThread(Thread):
  def __init__(self, *args, **keywords):
    Thread.__init__(self, *args, **keywords)
    self.killed = False

  def start(self):
    """Start the thread."""
    self.__run_backup = self.run
    self.run = self.__run # Force the Thread to install our trace.
    Thread.start(self)

  def __run(self):
    """Hacked run function, which installs the
    trace."""
    sys.settrace(self.globaltrace)
    self.__run_backup()
    self.run = self.__run_backup

  def globaltrace(self, frame, why, arg):
    if why == 'call':
      return self.localtrace
    else:
      return None

  def localtrace(self, frame, why, arg):
    if self.killed:
      if why == 'line':
        raise SystemExit()
    return self.localtrace

  def kill(self):
    self.killed = True

class SimpleThread (KThread):
  def __init__ (self, i, time):
    KThread.__init__ (self, name = "Simple")

  def run (self):
    i = 0
    while True:
      # Некие вычислительные действия.
      i = i + 1

import time
A = []
N = 25

while True:
  for i in xrange(N):
    A = A + [SimpleThread (i, time.clock())]
    A[i].start()
    time.sleep(0.5)
    A[i].kill()
    time.sleep(0.5)

python2.4 test.py - какое-то время выполняется, затем завершает программу без сообщений (хотя она должна крутиться бесконечно).

python2.5 выводит:

Error in sys.excepthook:

Original exception was:
- и тоже завершает программу.

То есть, по какой-то причине «прибивается» основной процесс.

Может быть это потому, что не делал join() после start()? (смысла join'а я не понимаю) Но если сделать join после start'а, то это очень тормозит весь процесс ...

pacify ★★★★★
() автор топика
Ответ на: комментарий от tia

> Есть и ситуация, когда поток в теле не имеет самого цикла ...

Да, мне нужно именно завершение run'а без цикла.
Нашел две реализации (см. выше ссылки) с Exception'ами.

pacify ★★★★★
() автор топика
Ответ на: комментарий от tia

> ... а в while True

Ты не понял. Мне нужна бесконечно работающая программа, но прибивающая свои подпроцессы (нити) по таймауту.

pacify ★★★★★
() автор топика
Ответ на: комментарий от pacify

Если я кидаю простой Exception вместо SystemExit(), то выдается типа такого:

Traceback (most recent call last):
  File "/usr/lib/python2.5/StringIO.py", line 213, in write
    _complain_ifclosed(self.closed)
  File "/usr/lib/python2.5/StringIO.py", line 213, in write
    _complain_ifclosed(self.closed)
  File "./test.py", line 297, in localtrace
    raise Exception
Exception
Exception: [get] [(23, 'Failed writing body (0 != 1113)')]
(исключение далеко внутри тела run, там, где у меня SGMLParser).

Ограничение try ... except'ами не помогает:

def run (self):
  try:
    ...
  except:
    pass

pacify ★★★★★
() автор топика
Ответ на: комментарий от pacify

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

И на python2.7 висит бесконечно. И еще очень смущает SystemExit, насколько я понимаю оно все и рушит.

P.S. Для вычислительных задач надо использовать multiprocessing.

baverman ★★★
()
Ответ на: комментарий от tia

Сорри, вопрос снимается.
В программе была ошибка - делался kill() над главным процессом,
индекс которого брался вместо индекса thread'ов.

pacify ★★★★★
() автор топика
Ответ на: комментарий от baverman

> Для вычислительных задач надо использовать multiprocessing.

Да, возможно для некоторых задач стоит юзать popen2() и аналоги.

pacify ★★★★★
() автор топика
Ответ на: комментарий от pacify

Вот так у меня работает.

import sys
from threading import Thread

class Kill(Exception): pass

class KThread(Thread):
  def __init__(self, *args, **keywords):
    Thread.__init__(self, *args, **keywords)
    self.killed = False

  def start(self):
    """Start the thread."""
    self.__run_backup = self.run
    self.run = self.__run # Force the Thread to install our trace.
    Thread.start(self)

  def __run(self):
    """Hacked run function, which installs the
    trace."""
    sys.settrace(self.globaltrace)
    try:
        self.__run_backup()
    except Kill:
        pass
    print 'exited'
    self.run = self.__run_backup

  def globaltrace(self, frame, why, arg):
    if why == 'call':
      return self.localtrace
    else:
      return None

  def localtrace(self, frame, why, arg):
    if self.killed:
      if why == 'line':
        raise Kill()
    return self.localtrace

  def kill(self):
    print 'killed'
    self.killed = True

class SimpleThread (KThread):
  def __init__ (self, i, time):
    KThread.__init__ (self, name = "Simple")

  def run (self):
    i = 0
    while True:
      i = i + 1

import time

a = SimpleThread (1, time.clock())
b = SimpleThread (1, time.clock())

a.start()
b.start()

time.sleep(1)

a.kill()
b.kill()

baverman ★★★
()
Ответ на: комментарий от pacify

А я то забыл, да, нужно спать больше... baverman прав, для таких задач _нужно_ использовать мультипроцессинг(это модуль пайтона, который имеет идентичный набор функций, но использует отдельные процессы и даёт немного дополнительных фишек.
Потоки в пайтоне достаточно специфичны, как и в рубях и некоторых ещё языках. Нельзя завершить на пайтоне поток, который выполняет некоторые вычислительные функции(например, ты не сможешь убить поток, выполняющий 22423543**23423432), хотя я точно сказать не могу, давно не работал с такими вещами.
Мультипроцессинг позволяет выделять всю функцию и её контекст в отдельный процесс пайтона, где оно выполняется отдельно от основного приложения.

tia
()

Какой ужас.

А вы не пробовали на ивентах сделать? Все равно параллельного выполнения у вас не будет никакого, зато не придется городить безумие, которое у вас написано. Ну или multiprocessing, в крайнем случае.

Не помню, когда в последний раз использовал thread/threading «вручную».

Кстати, по вашей ссылке на SO все правильно расписали - просто вот так «убивать» треды - бессмысленно и опасно. Взводите флаг, который в очередной итерации цикла в треде проверяется и, по необходимости, цикл завершается.

Наплодили тут сами себе проблем.

shylent
()

А что, вызывать thread.exit() (как вариант, sys.exit()) в потоке не тру?

anonymous
()
Ответ на: комментарий от tensai_cirno

Закапывать Вы будете? Судя по компетентности комментария, Вы как раз лопатой работать предпочитаете. thread — встроенный в интерпретатор («built-in») модуль для низкоуровневой работы с потоками. threading — модуль на python, фактически «обёртка» к thread, для удобной организации распоточивания. multiprocessing — симулирует привычный интерфейс threading, но уже для работы с процессами. Где тут три модуля для трединга? Для распараллеливания, да. И что, это плохо?

anonymous
()
Ответ на: комментарий от tensai_cirno

Нет, сырна. Просто пайтон не ограничивается мультипочностью. В пайтоне есть и мультипроцессинг.
Сырна не знает что такое мультипроцессинг?
Это проблемы бедной сырны, которая не уходила дальше своих рубей.
Что поделать.

tia
()
Ответ на: комментарий от tia

Толсто. Всё равно питон от этого адекватном не становится. Какой там у нас футпринт выходит, метров по двадцать на процесс? Еще небось и течет все как мартовская кошка.

tensai_cirno ★★★★★
()
Ответ на: комментарий от tensai_cirno

Угу, оналитеги такие оналитеги.

Всё равно питон от этого адекватном не становится.

Обсирая языки, оналитег от этого адекватом не становится. Если бы процессы по двадцать метров кушали, то отправились бы в топку вместе с модулем. Ан нет. Никто не матерится вроде по такому поводу.

anonymous
()
Ответ на: комментарий от tensai_cirno

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

tia
()
Ответ на: комментарий от tensai_cirno

Руби? В пастах твоих сообщений от фары, конечно.
А ты, возможно, не суёшь руби везде, поэтому везде кроме веба и сосёшь.

tia
()
Ответ на: комментарий от tia

Какой фары? Я не понимаю, над тобой надругались в переулке рельсовики? Или латентная злость питонистов на всё и вся? И пользуемся не только рубями, m`kay?

tensai_cirno ★★★★★
()
Ответ на: комментарий от tensai_cirno

Ну как хочешь.
При чём тут рельсовики? Просто ты плохой кодер, потому как приказываешь закопать всё и вся, хотя ничего и не знаешь, а главное - за рамки руби не хочешь выходить.
Хотя и верно, за пределами твоей клетки опасно, питонисты закусают!

tia
()
Ответ на: комментарий от tensai_cirno

> В питоне три разных модуля для трединга?

pthread_kill - Linux, libpthread.{so,a}
TerminateThread - Win32 API

К питону они отношения не имеют.

pacify ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.