Форум сайта python.su
Привет всем.
У меня странная проблема… Как и всегда…
import os
import sys
import signal
import config
import core
def start():
global core_main
core_main = core.Core()
core_main.start()
def stop():
print "Stoping..."
core_main.stop()
if __name__ == '__main__':
signal.signal(signal.SIGINT, lambda *a: stop())
start()
Отредактировано (Июнь 20, 2010 15:38:40)
Офлайн
Решил переопределением join в нити вот таким образом:
def join(self):
while not self.is_alive():
time.sleep(1.0)
Офлайн
Всем доброго времени суток!
Данная проблема получила продолжение.
Есть некий поток:
class RPCThread(threading.Thread):
flag_stop = True
def __init__(self):
super(RPCThread, self).__init__()
addr = (config.RPC_SERVER_ADDRESS, config.RPC_SERVER_PORT)
self.rpc = SimpleXMLRPCServer(addr)
self.log = logging.getLogger(self.__class__.__name__)
def stop(self):
self.log.info("Stoping")
self.flag_stop = True
def run(self):
self.log.info("Starting")
self.flag_stop = False
...
self.serve_forever()
def join(self):
while not self.isAlive():
time.sleep(1.0)
def serve_forever(self):
"""Handle requests while stop"""
while not self.flag_stop:
self.handle_request()
...
Офлайн
Всем доброго времени суток!
Разобрался я в этой проблеме. Имя ей - GIL. Более подробное описание наших изысканий:
Есть некая программа, которая должна одновременно выполнять 2-е функции: Собирать некие данные и общаться с клиентами(т е передавать им данные). Т к недопустимо, чтобы клиенты ждали конца сбора данных, то логично выделать 2-е разные нити под эти процессы - тогда сбор данных и общение с клиентами будет вестись параллельно. обращаю ваше внимание на один момент - НЕЛЬЗЯ предсказать, когда каждая из этих нитей завершится. Теоретически они могут работать бесконечно. Практически же - до тех пор, пока администратор не остановит.
Первое решение которое приходит в голову - в этих потоках запускаем бесконечный цикл с проверкой флага:
flag_stop = False
while not flag_stop:
time.sleep(1.0)
Guido van RossumА что это он говорил про timeout? Изучив документацию видим, что в join можно передать некоторую задержку. А что же она нам дает? Дальше начинаются мои собственные изыскания - опытным путем было установлено, что блокировка не наступает, до тех пор, пока не истечет задержка. Т е передали 10 - в течении 10 сек можно передать сигнал и он сработает как планировалось. Но после - увы - все по прежнему. Т к предсказать интервал, за который отработают процессы я не могу - он бесконечен, то этот путь нам не подходит.
This is because the regular acquire() method on a basic lock cannot be interrupted. That's unlikely to go away, so you'll just have to live with this. As you've discovered, specifying a timeout solves the issue (sort of).
Офлайн
Нить действительно должна завершать сама себя при “сигнале” снаружи. Под сигналом я имею ввиду любой флаг, функцию… Но синхронизация нитей сокетом и уж тем более файлом – отбойным молотком тараканов глушить! Оно может и работает, но уж совсем некрасиво. Да и проблема у нас немного в другом, если я правильно её вижу.
У нас нить-то (метод run) как раз завершается. Притом завершается от спокойно и красиво.По обычному флагу. А вот метод isAlive всё равно говорит, что нить работает. Т.е. проблема не в том, что нить не завершается, а в том, что threading.Thread всё равно думает, что нить работает.
Хорошо, будем думать, что это GIL. Просто после окончания работы нити, она пытается взять лок, чтобы сказать о том, что она закончила работу и ждёт его до второго пришествия.
Истина где-то рядом…
Офлайн
ZZZ, ты забываешь про еще один момент. Ты написал свой join, он получится проще и без lock. А как ты думаешь, зачем вообще написали такой вот join который есть сейчас? Ведь твой вариант гораздо проще и очевиднее. Я приведу здесь содержимое этого join:
def join(self, timeout=None):
if not self.__initialized:
raise RuntimeError("Thread.__init__() not called")
if not self.__started.is_set():
raise RuntimeError("cannot join thread before it is started")
if self is current_thread():
raise RuntimeError("cannot join current thread")
if __debug__:
if not self.__stopped:
self._note("%s.join(): waiting until thread stops", self)
self.__block.acquire()
try:
if timeout is None:
while not self.__stopped:
self.__block.wait()
if __debug__:
self._note("%s.join(): thread stopped", self)
else:
deadline = _time() + timeout
while not self.__stopped:
delay = deadline - _time()
if delay <= 0:
if __debug__:
self._note("%s.join(): timed out", self)
break
self.__block.wait(delay)
else:
if __debug__:
self._note("%s.join(): thread stopped", self)
finally:
self.__block.release()
Отредактировано (Июль 15, 2010 22:06:19)
Офлайн
Да, я согласен – блок нужен. Можно написать так…
def join(self, timeout=1.0):
while self.isAlive():
super(threading.Thread, self).join(timeout)
Офлайн
ZZZПопробовал. Написал вот такой пример -
У меня сейчас не получается заняться такими проверками… Попробуешь?
Оно должно работать с обычным флагом.
#!/usr/bin/env python
# vim: sw=4 ts=4 expandtab ai
import time
import threading
import signal
class Trtest(threading.Thread):
def __init__(self):
self.flagstop = False
super(Trtest, self).__init__()
def run(self):
print "start"
self.flagstop = False
while not self.flagstop:
print "run loop flag =", self.flagstop
time.sleep(1.0)
def join(self, timeout=1.0):
while self.isAlive():
super(Trtest, self).join(timeout)
def stop(self):
print "stop"
self.flagstop = True
t = Trtest()
signal.signal(signal.SIGINT, lambda *a: t.stop())
t.start()
t.join()
print "Done!"
super(threading.Thread, self).join(timeout)
super(Trtest, self).join(timeout)
alex@kubu-book:~/development/PYTHON_projects$ python ./threadtest.py
start
run loop
Traceback (most recent call last):
File "./threadtest.py", line 32, in <module>
t.join()
File "./threadtest.py", line 23, in join
super(threading.Thread, self).join(timeout)
AttributeError: 'super' object has no attribute 'join'
Exception AttributeError: "'super' object has no attribute 'join'" in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored
alex@kubu-book:~/development/PYTHON_projects$ python ./threadtest.py
start
run loop flag = False
run loop flag = False
run loop flag = False
run loop flag = False
^Cstop
Done!
alex@kubu-book:~/development/PYTHON_projects$
for i in `seq 100`; do python ./threadtest.py & sleep $i; kill -2 %1; sleep 2.0; done
Офлайн
Alex2ndrВот блин… Косячу… Сорри.
Только join немного переделал.
Alex2ndr:-) Красиво!
Даже вот так протестировал:
Alex2ndrДа вроде не должно. Давай пока так, это действительно правильнее, чем цеплять к rpc то, что ему не свойственно.
Я правда не знаю что там с этим таймаутом. Не будет ли какого косяка от того что там идет ожидание.
Офлайн
Переделал в проекте назад на сигналы. Только на обычных флагах он что-то подвисает. Останавливается не с 1-го сигнала, а со 2-го или 3-го. И тормозит в остановке. Не знаю почему так. Сделал на threading.Event - вроде таких граблей нет. Я постараюсь сделать примерчик, чтобы понять где он там висит.
Офлайн