Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 27, 2013 17:15:10

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Потоки

CommonUser
Скажите пожалуйста, как создать новый поток и использовать его несколько раз, то есть запускать, а не создавать снова. Python 2.7
Опишите, что хотите сделать. Думаю, все-таки нужна очередь.

Офлайн

#2 Март 5, 2013 10:55:16

CommonUser
Зарегистрирован: 2013-02-25
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Потоки

Да про очереди и задачи, я понял и разобрался. У меня теперь вопрос в другом:

from datetime import datetime
import sys
import threading
import time
def timed_run(func, args=(), kwargs={}, timeout=None):
    class TimedThread(threading.Thread):
        """An abortable thread, by merly raising an exception inside its
        context.
        """
        def __init__(self):
            super(TimedThread, self).__init__()
            self.exc_info = (None, None, None)
        def run(self):
            self.started_at = datetime.now()
            try:
                self.result = func(*args, **kwargs)
            except:
                # save the exception as an object attribute
                self.exc_info = sys.exc_info()
                self.result = None
            self.ended_at = datetime.now()
        def abort(self):
            self.ended_at = datetime.now()
            raise RuntimeError("Thread aborted as requested.")
    t = TimedThread()
    t.start()
    t.join(timeout)
    if t.exc_info[0] is not None:  # if there were any exceptions
        t, v, tb = t.exc_info
        raise t, v, tb  # Raise the exception/traceback inside the caller
    if t.is_alive():
        t.abort()
        diff = t.ended_at - t.started_at
        raise RuntimeError("%(f)s timed out after %(d)r seconds" %
                {'f': func, 'd': diff.seconds})
    return t.result
def func():
    # Unstoppable func
    while True:
        print "I am an unstoppable"
        time.sleep(5)
    return "done"
if __name__ == '__main__':
    print timed_run(func=func,timeout=10)

Как остановить программу в этом случае. Таймаут не сработает

Отредактировано CommonUser (Март 5, 2013 10:56:01)

Офлайн

#3 Март 5, 2013 19:35:32

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Потоки

Вот описание почему
http://eli.thegreenplace.net/2011/08/22/how-not-to-set-a-timeout-on-a-computation-in-python/
там же и что делать.
Вкратце: для nix - сигналы, для win - процессы, а еще лучше контролировать завершение работы внутри потока (функции).

Есть еще одно “полурешение”:

from threading import Timer
import thread
import time
 
 
class TimeoutError(Exception):
    """Function timed out"""
 
 
def timed_run(func, args=(), kwargs={}, timeout=None):
    start = time.time()
    try:
        Timer(timeout, thread.interrupt_main).start()
        return func(*args, **kwargs)
    except KeyboardInterrupt:
        raise TimeoutError("%s timed out (%.2f seconds)" % 
                            (func, time.time() - start))
 
 
def func():
    # Unstoppable func
    while True:
        print "I am an unstoppable"
        time.sleep(5)
     return "done"
if __name__ == '__main__':
    print timed_run(func=func,timeout=1.0)
Но оно прерывает исполнение не сразу. И от операции типа 50000**5000000000 не спасет.

Офлайн

#4 Март 6, 2013 02:51:08

CommonUser
Зарегистрирован: 2013-02-25
Сообщения: 14
Репутация: +  0  -
Профиль   Отправить e-mail  

Потоки

Автор в блоге пишет.

So even more sophisticated “solutions” propose to ditch the Python-level-API and just brutally kill a thread with pthread_kill (on Unix) or TerminateThread (on Windows). This is a very bad idea.

Придётся на multiprocessing переходить или на библиотеку гринлетов

Что-то вроде:

from multiprocessing.process import Process
import time
    
def func():
    while True:
        print "I am an unstoppable"
        time.sleep(1)
    
result = None
timeout = 15 
p = Process(target=func)
p.start()
    
# waiting for timeout
p.join(timeout)
    
print "timeout has elapsed or process has finished"
    
if p.is_alive():
    p.terminate()
    print "terminating the process"
    
time.sleep(10)
print "p.is_alive = %r" % p.is_alive()

И с получением результата от функции:
import multiprocessing
import time
    
resultq = multiprocessing.Queue(1)
    
def func1():
    while True:
        print "I am an unstoppable"
        time.sleep(1)
    #time.sleep(5)
    return True
    
def func2():
    time.sleep(5)
    return "Result of func2"
    
def _func(func=None, func_args=()):
    result = func(*func_args)
    resultq.put(result)       
    
def timedoutRun(func=None, f_args=()):
    timeout = 10
    result = None
        
    p = multiprocessing.Process(target=_func, args=(func,)+f_args)
    p.start()
        
    # waiting for timeout
    p.join(timeout)
    print "timeout has elapsed or process has finished"
    
    if resultq.empty():
        print "We do not have a result of func because of the func gets stuck"
    else:
        print "process has competed"        
        result = resultq.get()
        print "result is %r" % result
        
    if p.is_alive():
        p.terminate()
        print "terminating the process"
         
    time.sleep(10)
    print "p.is_alive = %r" % p.is_alive()
    
    return result
    
    
if __name__ == '__main__':
    print "start"
    print timedoutRun(func1)
    print timedoutRun(func2)
    print "end"
    

Не знаю как тут сделать правильно.
Пришлось держать глобальную очередь (которая может рассинхронизироваться при определённых условиях)

Отредактировано CommonUser (Март 6, 2013 08:54:56)

Офлайн

#5 Март 20, 2013 12:15:51

lorien
От:
Зарегистрирован: 2006-08-20
Сообщения: 755
Репутация: +  37  -
Профиль  

Потоки

> Есть Queue, внутри них используются локи. Код да, странный, я не обращал внимания на параметры).
> Видимо тут автор просмотрел это, а так параметры всё равно глобально передаются, то всё так и осталось работать.

Fixed https://bitbucket.org/lorien/grab/commits/c448bd767c974b501d6878312ebd6da073014bd1

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version