Найти - Пользователи
Полная версия: Потоки
Начало » Python для новичков » Потоки
1 2
reclosedev
CommonUser
Скажите пожалуйста, как создать новый поток и использовать его несколько раз, то есть запускать, а не создавать снова. Python 2.7
Опишите, что хотите сделать. Думаю, все-таки нужна очередь.
CommonUser
Да про очереди и задачи, я понял и разобрался. У меня теперь вопрос в другом:

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)

Как остановить программу в этом случае. Таймаут не сработает
reclosedev
Вот описание почему
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 не спасет.
CommonUser
Автор в блоге пишет.

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"
    

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

Fixed https://bitbucket.org/lorien/grab/commits/c448bd767c974b501d6878312ebd6da073014bd1
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB