Я должен записать простое приложение, которое выполняет два потока: - поток 1: выполнения в синхронизированные периоды, скажем, каждая 1 минута - распараллеливает 2: просто 'нормальное', в то время как Истинный цикл, который действительно 'наполняет'
если бы не требование для выполнения в синхронизированном интервале я не посмотрел бы на скрученный вообще, но простой сон (60) не достаточно хорош и конструкция как:
l = task.LoopingCall(timed_thread)
l.start(60.0)
reactor.run()
Посмотревший действительно простой достигнуть того, что я хотел там.
Теперь, как я 'правильно' добавляю другой поток?
Я вижу две опции здесь:
Вот то, что я придумал:
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 разбомбил для окружения, и если я тогда 'уничтожаю %1', это, кажется, уничтожает процесс (оболочка сообщает, что), но 'нормальный' поток продолжает работать. уничтожьте PID, не избавился бы от него, и единственное средство исправления является уничтожением-9. Действительно странный.
Так. Что я делаю неправильно? Действительно ли это - корректный подход для реализации двух потоков в скрученном? Разве я не должен беспокоиться скрученным? Что другие 'стандартные' альтернативы должны реализовать синхронизированные вызовы? ('Стандарт', я подразумеваю, что могу easy_install или конфетка, устанавливает их, я не хочу начинать загружать и использовать некоторые случайные сценарии от случайных веб-страниц).
Предполагая, что ваш main относительно неблокирующий:
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
Вы не объяснили, зачем вам на самом деле нужны потоки. Если бы вы объяснили, я бы смог объяснить, почему они вам не нужны. ;)
Что касается этого, я могу подтвердить, что ваше базовое понимание вещей верно. Одно возможное недоразумение, которое я могу прояснить, это представление о том, что "потоки python" и "потоки Twisted" вообще отличаются друг от друга. Это не так. Python предоставляет библиотеку потоков. Все API потоков Twisted реализованы в терминах библиотеки потоков Python. Отличается только API.
Что касается завершения работы, у вас есть два варианта.
reactor.addSystemEventTrigger('before', 'shutdown', f)
. В этом хуке установите связь с рабочим потоком и скажите ему выключиться. Например, вы можете разделить threading.Event
между потоком Twisted и вашим рабочим потоком, а хук установить
его. Рабочий поток может периодически проверять, был ли он установлен, и завершать работу, когда заметит, что он был установлен. Помимо отсутствия сбоев, это дает еще одно преимущество перед потоками-демонами - это позволит вам выполнить некоторый код очистки или завершения в рабочем потоке перед завершением процесса.