Темы в витой ... как правильно их использовать? - PullRequest
9 голосов
/ 11 февраля 2010

Мне нужно написать простое приложение, которое запускает два потока: - поток 1: выполняется в определенные периоды времени, скажем, каждую минуту - поток 2: просто «нормальный» цикл True, который выполняет «вещи»

если бы не требование работать с определенным интервалом, я бы вообще не смотрел на скрученность, но простой сон (60) не достаточно хорош и конструкция вроде:

l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.run()

Выглядело очень просто, чтобы достичь того, чего я хотел там.

Теперь, как мне "правильно" добавить другую ветку?

Я вижу здесь два варианта:

  • Используйте библиотеку потоков и запустите два «потока python», один из которых выполняет мой цикл while, а другой - в реактор.run (). Но Google, похоже, возражает против такого подхода и предлагает использовать витую многопоточность
  • Использовать витую резьбу. Это то, что я пробовал, но как-то мне это кажется немного неуклюжим.

Вот что я придумал:

def timed_thread():
    print 'i will be called every 1 minute'
    return

def normal_thread():
    print 'this is a normal thread'
    time.sleep(30)
    return

l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.callInThread(normal_thread)
reactor.run()

Это похоже на работу, но! Я не могу остановить приложение. Если я нажму ^ C, он ничего не сделает (без 'callInThread' он просто остановится, как вы и ожидаете). ^ Z разлетается в оболочку, и если я затем произвожу 'kill% 1', он, кажется, завершает процесс (оболочка сообщает об этом), но "нормальный" поток продолжает работать. kill PID не избавился бы от этого, и единственное лекарство - это kill -9. Действительно странно.

Итак. Что я делаю неправильно? Это правильный подход для реализации двух потоков в витой? Должен ли я не заморачиваться с витой? Какие еще «стандартные» альтернативы предназначены для осуществления синхронизированных вызовов? («Стандартный», я имею в виду, что я могу easy_install или yum установить их, я не хочу начинать загрузку и использование некоторых случайных сценариев со случайных веб-страниц).

Ответы [ 2 ]

5 голосов
/ 11 февраля 2010

Вы не объяснили, зачем вам здесь нужны темы. Если бы ты это сделал, я мог бы объяснить, почему они тебе не нужны. ;)

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

Что касается выключения, у вас есть два варианта.

  • Запустите ваш поток выполнения навсегда, используя потоковые API-интерфейсы Python, и сделайте поток демоном. Ваш процесс может завершиться, даже если потоки демона еще работают. Возможная проблема, связанная с этим решением, заключается в том, что в некоторых версиях Python есть проблемы с потоками демонов, которые могут привести к сбою во время завершения работы.
  • Создайте свой поток, используя либо API-интерфейсы Twisted, либо API-интерфейсы потоков stdlib, но также добавьте хук Twisted shutdown, используя reactor.addSystemEventTrigger('before', 'shutdown', f). В этом хуке свяжись с рабочим потоком и скажи ему выключиться. Например, вы можете разделить threading.Event между витой нитью и вашей рабочей нитью и получить хук set it. Рабочий поток может периодически проверять, установлен ли он, и завершать работу, когда замечает, что он установлен. Помимо не сбоя, это дает еще одно преимущество перед потоками демона - оно позволит вам выполнить некоторый код очистки или завершения в вашем рабочем потоке до завершения процесса.
2 голосов
/ 11 февраля 2010

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

import random
from twisted.internet import task

class MyProcess:
  def __init__(self):
    self.stats = []
    self.lp = None
  def myloopingCall(self):
    print "I have %s stats" % len(self.stats)
  def myMainFunction(self,reactor):
    self.stats.append(random.random())
    reactor.callLater(0,self.myMainFunction,reactor)
  def start(self,reactor):
    self.lp = task.LoopingCall(self.myloopingCall)
    self.lp.start(2)
    reactor.callLater(0,self.myMainFunction,reactor)
  def stop(self):
    if self.lp is not None:
      self.lp.stop()
    print "I'm done"

if __name__ == '__main__':
  myproc = MyProcess()
  from twisted.internet import reactor
  reactor.callWhenRunning(myproc.start,reactor)
  reactor.addSystemEventTrigger('during','shutdown',myproc.stop)
  reactor.callLater(10,reactor.stop)
  reactor.run()
$ python bleh.py
I have 0 stats
I have 33375 stats
I have 66786 stats
I have 100254 stats
I have 133625 stats
I'm done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...